From ae644e1360f63f2ad91c350ec6f0e5d4b9eb1ac8 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 5 Aug 2026 09:04:49 +0000 Subject: [PATCH] =?UTF-8?q?test(qa):=20dogfood=20=E7=9C=9F=E5=AE=9E=20boot?= =?UTF-8?q?=20=E6=8A=8A=20cacheTtl=20=E7=9A=84=20`private`=20=E4=B8=80?= =?UTF-8?q?=E5=B9=B6=E9=92=89=E4=BD=8F,=E4=B8=8D=E5=8F=AA=E9=92=89=20max-a?= =?UTF-8?q?ge=20(#5396)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit showcase-declarative-endpoints.dogfood.test.ts 是整条 cacheTtl 链上唯一 观测真实 wire 的一层,而它此前只钉 /max-age=30/,漏掉了 `private` —— 链上唯一有安全含义的那一位。实测:把 computeCacheControl 临时改成 public 后,旧断言依然全绿。 改为整行钉 /^private, max-age=30$/(实测真实 wire 值就是这一整串, 无附加指令,故整行钉法不脆断)。仅此一条断言;运行时、showcase 声明、 以及 :213 那条「错误答案不得带缓存指令」的断言均未改动。 Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_016FNvXhtSdnEGEfLEsMmvxh --- ...case-declarative-endpoints.dogfood.test.ts | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/qa/dogfood/test/showcase-declarative-endpoints.dogfood.test.ts b/packages/qa/dogfood/test/showcase-declarative-endpoints.dogfood.test.ts index 92ee6e236b..95ce3b33b2 100644 --- a/packages/qa/dogfood/test/showcase-declarative-endpoints.dogfood.test.ts +++ b/packages/qa/dogfood/test/showcase-declarative-endpoints.dogfood.test.ts @@ -197,10 +197,27 @@ describe('[#5112] object_operation endpoint: same pipeline, same answer', () => expect(a.data).toEqual(b); }); - it('carries the declared cacheTtl as a Cache-Control header', async () => { + it('carries the declared cacheTtl as a Cache-Control header — `private` included', async () => { + // Both halves of this header are pinned, and the FIRST one is the reason + // this assertion exists at all (#5396). + // + // `private` is not a tuning choice on this chain, it is a security rule: + // every endpoint answer may have been trimmed per-caller by RLS, so a + // shared cache must never store one and hand it to somebody else. The + // producer states that in `computeCacheControl` + // (`packages/runtime/src/endpoint-policy.ts`), and the unit tests below it + // pin the RETURN VALUE. This assertion is the only layer that sees what a + // caller actually receives after the whole stack has run — so if any layer + // between the policy chain and the socket ever rewrites `private` to + // `public`, this is the only place that can notice. It pinned `max-age=30` + // alone until #5396, i.e. it would have stayed green through exactly that + // rewrite. const res = await stack.apiAs(adminToken, 'GET', TASKS); - expect(res.headers.get('cache-control'), 'cacheTtl: 30 must reach the wire').toMatch(/max-age=30/); - }); + expect( + res.headers.get('cache-control'), + 'cacheTtl: 30 must reach the wire, and reach it as `private`', + ).toMatch(/^private, max-age=30$/); + }, 60_000); it('DENIES an anonymous caller with 401 — authRequired finally gates', async () => { // The security semantic #4936 found parsing green and enforcing nothing.