Repository navigation
Add cache-header audit design spec for ts origin audit-headers - #930
Conversation
aram356
left a comment
There was a problem hiding this comment.
Summary
The spec is a solid starting shape for ts dev audit headers (clear taxonomy, verdict rollup, task breakdown), but several load-bearing claims about the codebase are stale or incorrect — ts dev is already a subcommand tree, there is no CliError enum, reqwest is not a CLI dependency, and the discovery section probes edge-only /_ts/ routes against the publisher origin. Two cacheability rules also fail the strictest correct configuration, and the doc itself is what's breaking the format-docs CI check.
Details are in the inline comments (8 blocking 🔧, 5 🤔, 1 ♻️, 2 🌱, 2 ⛏). Cross-cutting items below.
Blocking
🔧 wrench
- format-docs CI failure: prettier rejects this file's tables —
cd docs && npm run format:write(line 30) - Dependency graph must be mermaid: docs use vitepress-plugin-mermaid; ASCII art won't render (line 391)
- Stale
ts devpremise:DevCommandsubcommand tree already exists on main; noServeto default to (lines 254, 289) CliErrordoesn't exist: CLI errors areCliResult<T> = Result<T, String>(line 271)reqwestis not a CLI dep + target scoping unaddressed: workspace default target iswasm32-wasip1; spec must say where deps are scoped and that audit is cross-platform, unlike the macOS-only proxy (line 323)- Discovery probes edge routes against origin:
/_ts/*paths 404 onpublisher.origin_url(line 131) - Wrong issue link: #293 text links to /issues/834 (line 7)
- HTML/RTB rules fail
no-storealone: RFC 9111's strongest posture would FAIL the audit (lines 75, 106)
Non-blocking
📌 out of scope
- Plan document and epic breakdown still pending: issue #835 asks for a spec and a plan under
docs/superpowers/plans/plus a task breakdown in epic #834; this PR delivers the spec only (Section 10 is a partial plan). Also, the PR body retains the unfilled template (empty Summary/Changes tables, danglingCloses #).
CI Status
- format-docs: FAIL (caused by this file)
- All other checks (fmt, clippy targets, Rust/JS tests, integration, parity, CodeQL): PASS
Technical spec for epic IABTechLab#834: origin cache-header audit with per-content-type cacheability diagnostics. Covers content-type taxonomy, cacheability rules for all five directives (Cache-Control, Surrogate-Control, Surrogate-Key, Vary, ETag), per-type verdict rollup, CLI integration into the ts dev group, and a 7-task implementation breakdown. Closes IABTechLab#835
Resolves all 8 blocking 🔧 items from @aram356's review: 1. format-docs CI: ran prettier (tables now padded correctly) 2. Dependency graph: replaced ASCII art with mermaid flowchart 3. Stale ts dev premise: rewrote §8.1 to add Audit variant to existing DevCommand enum (no Serve default, no DevArgs invention) 4. CliError: corrected §8.2 to use existing CliResult<T>/cli_error() pattern 5. reqwest scoping: added §8.3 explaining cfg(not(wasm32)) dep scoping and cross-platform requirement for audit (unlike macOS-only proxy) 6. Discovery probes: rewrote §5 to HTML-parse origin root page instead of probing edge-only /_ts/ routes against origin 7. Issue link: fixed [IABTechLab#293] to link to IABTechLab/issues/293 (was linking IABTechLab/issues/834) 8. HTML/RTB no-store rules: no-store alone now passes per RFC 9111 §5.2.2.5 Non-blocking items also addressed: - Verdict: changed to unit enum (messages on HeaderVerdict) - Author: corrected @Vasujai to @vasujain00 - s-maxage: added to audited headers with explanation - Vary: now evaluated on all cacheable groups (not just HTML) - application/woff*: removed (redundant with font/*) - Content-Type param stripping: documented in §3 - Module path: corrected to commands/dev/audit/headers/
cf69725 to
e268913
Compare
|
@vasujain00 Thank you for addressing Please implement it per spec. You can use this pr for the implementation as well. |
aram356
left a comment
There was a problem hiding this comment.
Summary
The round-1 blockers on the mermaid graph, the DevCommand premise, CliResult, bare no-store, and the #293 link are resolved. Since that round, main has changed under the spec: TS now sets HTML cache privacy itself, has an opt-in template cache and operator asset rules, and documents the CLI's exit codes and --json conventions. Several rules now contradict shipped behavior, and three design gaps (redirects, edge-vs-browser policy, per-URL results) would have the tool grade responses TS never serves. Most of the fixes land in §4, §5 and §7.2.
9 of the inline comments below carry a one-click GitHub
suggestion. Use Commit suggestion (or Add suggestion to batch for several at once) to apply them as commits on the PR branch. The remaining comments describe the fix in prose because it spans several sections of the spec.
Blocking
🔧 wrench
- HTML rule fails correct configs and disables the template cache: see inline at
2026-07-14-cache-header-audit-design.md:77-80 - Rules grade Cache-Control as the edge policy (Surrogate-Control, CDN-Cache-Control, Age, Expires ignored): see inline at
2026-07-14-cache-header-audit-design.md:71 immutablerecommended for unfingerprinted JS/CSS/fonts: see inline at2026-07-14-cache-header-audit-design.md:86- Exit code 2 collides with the CLI's tool-failure code: see inline at
2026-07-14-cache-header-audit-design.md:40-48 - Audit requests don't match what TS sends to origin: see inline at
2026-07-14-cache-header-audit-design.md:142-143 - Following redirects grades a different response than TS receives: see inline at
2026-07-14-cache-header-audit-design.md:457 - No per-URL record: verdicts can't name the URL; errors and status codes unmodeled: see inline at
2026-07-14-cache-header-audit-design.md:228-243 Set-Cookieisn't audited, and it overrides every other cache header: see inline at2026-07-14-cache-header-audit-design.md:67- RTB bullet still routes discovery to an edge-only route: see inline at
2026-07-14-cache-header-audit-design.md:141-145 - §4.6 still conflates request-side
If-None-Match(#428);Last-Modifiedmissing: see inline at2026-07-14-cache-header-audit-design.md:117-122 - §8.3's
reqwest = { workspace = true }makests dev proxypanic: see inline at2026-07-14-cache-header-audit-design.md:296
Non-blocking
- 🤔 All
application/jsongraded as RTB: see inline at2026-07-14-cache-header-audit-design.md:62 - 🤔 Placement:
ts auditis now the audit group: see inline at2026-07-14-cache-header-audit-design.md:314 - ♻️ Reuse
AppConfigArgsinstead of a new--config: see inline at2026-07-14-cache-header-audit-design.md:38 - 🤔 Bare
no-store: citation doesn't say "sufficient"; advise addingprivate: see inline at2026-07-14-cache-header-audit-design.md:115 - 🤔 Missing
Surrogate-KeyWARNs every non-Fastly deployment; message is inaccurate: see inline at2026-07-14-cache-header-audit-design.md:88 - 🤔 Discovery can't reach parts of the taxonomy: see inline at
2026-07-14-cache-header-audit-design.md:138-140 - 🤔 Fetcher has no host allowlist, limits, or output escaping: see inline at
2026-07-14-cache-header-audit-design.md:363 - ⛏ §8.1 snippet needs
#[command(subcommand)]: see inline at2026-07-14-cache-header-audit-design.md:277-278 - ⛏ Cross-platform rationale misstates the dependency facts: see inline at
2026-07-14-cache-header-audit-design.md:288 - ⛏
s-maxageis a directive, not a header: see inline at2026-07-14-cache-header-audit-design.md:69 - ⛏ Real domain in examples (human output): see inline at
2026-07-14-cache-header-audit-design.md:156 - ⛏ Real domain in examples (JSON): see inline at
2026-07-14-cache-header-audit-design.md:175-179 - ⛏ Task wiring details (args location, cfg cleanup, output writer): see inline at
2026-07-14-cache-header-audit-design.md:215 - 🌱 Test fixture reuse, acceptance cases, docs sidebar: see inline at
2026-07-14-cache-header-audit-design.md:412
Cross-cutting / body-level findings
- 📝 PR description is still the unfilled template: the Summary and Changes table are empty, and there's a dangling
Closes #below the realCloses #835. Worth filling in, especially if this PR will also carry the implementation.
CI Status
- Analyze (actions): PASS
- Analyze (javascript-typescript): PASS
- Analyze (rust): PASS
- browser integration tests: PASS
- cargo check (cloudflare native + wasm32-unknown-unknown): PASS
- cargo check/build/test (spin native + wasm32-wasip1): PASS
- cargo fmt: PASS (required)
- cargo test: PASS (required)
- cargo test (axum native): PASS
- cargo test (cross-adapter parity): PASS
- cargo test (ts CLI, native): PASS
- CLAUDE.md symlink guard: PASS
- CodeQL: PASS
- format-docs: PASS (required)
- format-typescript: PASS (required)
- integration tests: PASS
- integration tests (Fastly EC lifecycle): PASS
- prepare integration artifacts: PASS
- vitest: PASS
prk-Jr
left a comment
There was a problem hiding this comment.
Summary
The design document is unchanged since the September 24 review. Material specification issues remain in asset caching recommendations, HTML policy, effective cacheability, origin routing, dependency features, exit statuses, and result attribution. These need correction before this specification guides implementation.
This review contains seven blocking findings and one non-blocking documentation correction, all expressed as prose comments.
Blocking
- Avoid enabling a second rustls crypto provider — see inline at
docs/superpowers/specs/2026-07-14-cache-header-audit-design.md:301 - Gate immutable caching on verified versioned URLs — see inline at
docs/superpowers/specs/2026-07-14-cache-header-audit-design.md:86 - Separate HTML privacy from origin-template eligibility — see inline at
docs/superpowers/specs/2026-07-14-cache-header-audit-design.md:77 - Evaluate effective browser and shared-cache policies — see inline at
docs/superpowers/specs/2026-07-14-cache-header-audit-design.md:71 - Preserve configured origin routing and Host overrides — see inline at
docs/superpowers/specs/2026-07-14-cache-header-audit-design.md:142 - Reserve a distinct exit status for incomplete audits — see inline at
docs/superpowers/specs/2026-07-14-cache-header-audit-design.md:48 - Keep verdicts associated with individual sampled URLs — see inline at
docs/superpowers/specs/2026-07-14-cache-header-audit-design.md:228
Non-blocking
- Mark the nested clap subcommand — see inline at
docs/superpowers/specs/2026-07-14-cache-header-audit-design.md:278
Validation
- All 19 reported GitHub checks pass.
- The changed document passes local Prettier checking.
- Isolated dependency-feature and rustls builder reproductions confirm the crypto-provider conflict; the single-provider reproduction succeeds.
- The corrected nested clap derive compiles.
- The full runtime suite was not rerun locally for this documentation-only PR.
CI Status
- Analyze (actions): PASS
- Analyze (javascript-typescript): PASS
- Analyze (rust): PASS
- browser integration tests: PASS
- cargo check (cloudflare native + wasm32-unknown-unknown): PASS
- cargo check/build/test (spin native + wasm32-wasip1): PASS
- cargo fmt: PASS (required)
- cargo test: PASS (required)
- cargo test (axum native): PASS
- cargo test (cross-adapter parity): PASS
- cargo test (ts CLI, native): PASS
- CLAUDE.md symlink guard: PASS
- CodeQL: PASS
- format-docs: PASS (required)
- format-typescript: PASS (required)
- integration tests: PASS
- integration tests (Fastly EC lifecycle): PASS
- prepare integration artifacts: PASS
- vitest: PASS
Address the September 24 and October 1 review feedback, and rebase the design on what main now ships. - Move the command to `ts origin audit-headers`, next to `probe-shareability`, and defer the HTML shareability verdict to the probe. - Evaluate browser and shared-cache policy separately, with per-runtime precedence (Surrogate-Control, CDN-Cache-Control, Expires, Age), and apply TS overrides: asset rules, cookie privacy, and ad-serving and readthrough paths. - Recommend `immutable` only for fingerprinted URLs, audit Set-Cookie and validators (ETag or Last-Modified), and drop the request-side IABTechLab#428 framing. - Map URLs through asset routes and the Host override, never follow redirects across hosts, grade 3xx and error responses, and bound fetches. - Model per-URL results with status and errors, align JSON with `ts audit ad-templates verify`, and use exit codes 0/1/2 with --strict. - Reuse the CLI's existing reqwest client and rustls provider install instead of the workspace reqwest dependency. - Replace real domains with example domains, and rework tasks, tests, and open questions accordingly.
Merging since implementation started
…BTechLab#930) Addresses round-3 blockers IABTechLab#4, IABTechLab#5, IABTechLab#6 and splits IABTechLab#7. IABTechLab#4 placement: the merged design spec (IABTechLab#930, docs/superpowers/specs/ 2026-07-14-cache-header-audit-design.md §34) places this command at `ts origin audit-headers`, beside `ts origin probe-shareability`. Moved the module from commands/dev/audit/headers to commands/origin/audit_headers, removed the DevAuditCommand group, and added an AuditHeaders variant to OriginCommand. URLs now arrive through a repeatable --url (probe convention), not positional args. IABTechLab#5 exit codes: dropped the bespoke exit-code 3 and the process::exit call. The report now maps to RunOutcome (AssertionFailed on a FAIL, or a WARN under the new --strict flag; Success otherwise), returned through dispatch like every other command. main exits 2 for transport/config errors (Err), so a warn-only audit is never confused with one that could not run. Matches spec §59-69. IABTechLab#6 transport safety: explicit --url, the resolved origin root, and discovered assets all pass through the shared crate::url_guard::require_credential_safe_ transport used by probe-shareability -- HTTPS required except on loopback, no URL-embedded credentials. Discovery is additionally restricted to http/https assets, so file:/javascript:/data: links pulled from fetched HTML are dropped. IABTechLab#7 core-aware grading (Spec Task 1) is deliberately NOT in this change -- it spans trusted-server-core and is tracked as a follow-up (noted in the PR description). This command ships the generic ruleset. Docs: cli.md updated to the new command surface, --strict, and the 0/1/2 exit-code table. 776 CLI tests pass, clippy -D warnings clean, fmt + prettier clean.
Summary
ts origin audit-headers, a CLI command that audits publisher-origin cache headers and returns per-URL and per-content-type pass/warn/fail verdicts naming the responsible header and the value to set.main(Implement configurable cache header policies #860 cache-header policies, Split origin shareability from template eligibility, and add the readthrough evidence gate #1169ts origin probe-shareabilityand origin readthrough, the ESI template cache) and addresses the review rounds from 2026-08-14, 2026-09-24, and 2026-10-01.ts origin probe-shareability; this command covers what the probe doesn't: subresources, effective browser and shared-cache policy, TS overrides, redirects, and error responses.Changes
docs/superpowers/specs/2026-07-14-cache-header-audit-design.mdCloses
Closes #835
Test plan
cd docs && npm run format(prettier 3.8.1, the lockfile version, on the spec)OriginCommandshape against the workspace's clap 4.6.1asset_route_for_path,origin_host_header,asset_cache_policy_for_path,enforce_set_cookie_cache_privacy,match_slots,tls::install_crypto_provider, the template-cache gate) againstmainChecklist