fix: apply the recorded private Cache-Control matrix to image probes

TR-RR-09. The documented BT-IMG-02 contract requires a private response to
carry no-store and fail closed when any directive that describes cacheability
accompanies it. The probe checked only that no-store was present and public was
absent, and the suite pinned the contradictory "private, no-store" as a success.
Both now follow the recorded contract: only no-store and syntactically valid
unknown extensions are admitted, and public, private, immutable, max-age,
s-maxage, no-cache, must-revalidate and proxy-revalidate each fail closed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
DongHyeonka
2026-08-14 14:14:41 +09:00
co-authored by Claude Opus 5
parent efc577de63
commit fb5b449031
2 changed files with 86 additions and 4 deletions
@@ -310,9 +310,13 @@ function validResponseHeaders(
);
if (!directives) return false;
if (request.delivery === "PRIVATE_SIGNED") {
return (
directives.get("no-store") === true &&
!directives.has("public")
// TR-RR-09. The recorded BT-IMG-02 contract is a fail-closed matrix, not a
// pair of checks: a private response must carry `no-store` and nothing else
// that describes cacheability. Only a syntactically valid unknown extension
// is ignored, so a contradictory pairing can never read as acceptable.
if (directives.get("no-store") !== true) return false;
return !PRIVATE_FORBIDDEN_DIRECTIVES.some((name) =>
directives.has(name),
);
}
const maxAge = directives.get("max-age");
@@ -336,6 +340,21 @@ function validResponseHeaders(
);
}
/**
* TR-RR-09. Every cacheability directive a `PRIVATE_SIGNED` response may not
* carry alongside `no-store`.
*/
const PRIVATE_FORBIDDEN_DIRECTIVES: readonly string[] = Object.freeze([
"public",
"private",
"immutable",
"max-age",
"s-maxage",
"no-cache",
"must-revalidate",
"proxy-revalidate",
]);
/**
* BT-IMG-02. Quote- and escape-aware Cache-Control tokenizer.
*