test(dogfood): cover /actions and /automation in the anonymous-deny proof artifact (#5570) - #5631
Merged
Merged
Conversation
…roof artifact (#5570) `authz-conformance.matrix.ts` names `showcase-anonymous-deny-surfaces.dogfood.test.ts` as the proof artifact for #2567's "anonymous posture is uniform across HTTP surfaces" claim, but the suite drove only `/data` and `/meta`. #5519 found the claim false on exactly the two surfaces it did not drive — the dispatcher-mounted `/actions` and `/automation` — and the artifact was silent throughout. PR #5569 built the gate in `packages/runtime`; this is the evidence half. - six new anonymous cases on the shared showcase boot: POST a `script` action, POST `/automation/:name/trigger`, GET `/automation`, DELETE `/automation/:name` (all 401), plus the two authenticated contrasts. - one case pins that all four surfaces answer the same code and message, reading each family in its own declared envelope rather than through a tolerant `??` chain. - two matrix rows (`anonymous-deny-actions`, `anonymous-deny-automation`) with their `covers` keys, ratchet probes for both gates, and a `(h)` bites case, so deleting either gate fails CI as STALE covers. No `packages/runtime` change: this adds proof, not defence. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016FNvXhtSdnEGEfLEsMmvxh
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 2 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #5570
test-only。请 PM 打
skip-changeset标签 ——.github/workflows/pr-automation.yml的 changeset 门把 "tests-only" 明写为 route 2 且标注 PREFERRED;packages/qa/dogfood是private: true,不发版,不产生 changeset 输入。(我已自行贴上该标签以免 CI 无谓变红,如与 PM 流程冲突请摘掉。)前提复核(先证后改,rule 6)
分诊席 19:59Z 核过一次;我在动手时刻的
origin/main(7e58212) 上重核:前提成立。showcase-anonymous-deny-surfaces.dogfood.test.ts改动前共 4 条用例,覆盖面只有/meta×2 与/data/showcase_private_note×2,grep全文无/actions、无/automation。而authz-conformance.matrix.ts:90把该文件列为anonymous-deny-meta行的 proof 工件,该行所在的注释块声明的是 #2567「anonymous-deny posture is UNIFORM across HTTP surfaces」。这次补的证据比 #5569 自己的集成用例多出什么
#5569 的
dispatcher-plugin.anonymous-gate.integration.test.ts最后一条用例自己写明了它做不到的那半:本 PR 补的正是这半:showcase 真启动里,一个进程、两条注册路径(
@objectstack/rest供/data+/meta;dispatcher-plugin.ts把/actions+/automation直接挂到 host server)四个面并排断言。那条注册路径的分叉就是 #5519 之所以发生的原因。落点
三个文件,全部在
packages/qa/dogfood/test/,packages/runtime/**一行未动(git diff --stat -- packages/runtime为空)。1.
showcase-anonymous-deny-surfaces.dogfood.test.ts(+7 例,4 → 11)POST /actions/showcase_task/showcase_mark_done/anon-probe-idPOST /automation/showcase_reassign_wizard/triggerGET /automationDELETE /automation/showcase_reassign_wizard对象 / action / flow 名全取自 showcase 现有声明:
showcase_mark_done是showcase_task上的type: 'script'action(body 走api.write,即 #5519 实测匿名拿到 200 并真的落了写的那一条);showcase_reassign_wizard是 showcase 已声明的 flow。recordId 刻意用不存在的 id:门是
handleActionsRequest的第一条语句,匿名请求在任何对象 / action / 记录被解析之前就被拒。若非得先造一条真记录才能拿到 401,那说明门已经挪到了 lookup 后面。再加两条已认证对照,它们是这批用例牙齿的来源(见下)。
2. 信封:同一个 code 与 message,两种 wrapper —— 如实钉住
这里有一条与派发单预设不符、必须申报的事实。派发单要求「信封断言与套件内
/data、/meta现有条目逐字同形(同一 error/code 键)」。实测两族的 body 形状并不同:@objectstack/rest走ANONYMOUS_DENY_BODY的扁平信封,dispatcher 走它自己的 wrapper。这是 ADR-0112 修正案记录在案的两个 live 信封,不是本单引入的。所以我没有硬凑「逐字同形」,也没有写
??容忍链去把两种形状读成一种 —— 那正是 rule 5 要避免的宽容消费者。做法是:每族按各自声明的形状显式断言,再单独钉住真正统一的那层语义(同一 status / 同一 code / 同一 message),并注明 wrapper 分叉是已知平台事实。这样任何一族哪天变形都会红,而不是被容忍读悄悄吃掉。顺带发现
@objectstack/core的ANONYMOUS_DENY_BODY注释自称 "The single 401 body shape every seam returns",与上表不符 —— 已另行立单(见文末),未在本 PR 修。3.
authz-conformance.matrix.ts+.test.ts—— 登记惯例随行按 #2567 Phase 2 现有惯例(surface 行 =
enforcement+proof+covers,并进HIGH_RISK)补两行:anonymous-deny-actions→covers: ['actions:domains/actions.ts:anonymous-gate']anonymous-deny-automation→covers: ['automation:domains/automation.ts:anonymous-gate']并补两条
PROBES(形状与既有buildMcpBridge(context-threaded)/stdio-principal-bound这两条 gate pin 一致,而非 surface 探针)、一条(h)bites 用例。删掉任一侧的门 → key 消失 → 覆盖它的行 STALE → CI 红。反向验证(方向先判后跑)—— 分两阶段,方向不同
预判先写,并且故意不是「一律转红」:
POST /actions/...showcase_audit_task_completion的 hook condition 报错)。红/automation×3@objectstack/service-automation)。红/data、/meta×4@objectstack/rest,未触碰).not.toBe(401)与 501 钉子都不受门影响)阶段 A ——
if (false && shouldDenyAnonymous({...,重建 runtime逐条命中预判,
/data、/meta、两条已认证对照全绿。这里有一条值得单独说的:
/automation的「无门答案」是 501 而不是 200,因为本 boot 没装 automation 服务。这恰恰是那条已认证 501 对照用例存在的理由 —— 同一个进程、同一条路由,匿名 401 / 成员 501,两者并排,401 就只可能是门给的。这也是 #5569 刻意把门放在isServiceServeable探测之前的原因(否则 401 与 501 的差异会泄露该部署是否挂了 automation)。用例注释里写明了。conformance ratchet 在阶段 A 保持绿,这是预判之内:
if (false &&保留了shouldDenyAnonymous(这个 token,而 ratchet 钉的是调用的存在,不是它的活性 —— 与文件里既有的每一条 gate pin 同一性质。两层是互补的,这本身就是 #5570「光有 ratchet 不够、proof 工件必须真跑」的论据。阶段 B —— 真正删掉调用(
shouldDenyAnonymous→ 改名)还原后
git diff --stat -- packages/runtime为空。消费半径扫描
不按被改的包扫,按被改工件的 caller 扫:
grep -rn "authz-conformance"全仓(排除 node_modules)只命中packages/qa/dogfood内部,外加packages/spec/src/contracts/realtime-service.ts与plugin-security/src/authz-matrix-gate.test.ts两处纯注释引用,无代码依赖。proof 工件本身只被checkLedger按文件名存在性校验。实跑记录
自限
packages/qa/dogfood/test/,三个文件,+210 行 / -0 行。未触碰packages/runtime/**(防线本体)、未触碰其他 dogfood 套件、未触碰content/docs/releases/。shared-showcaseproject(plainbootStack(showcaseStack)),未改vitest.config.ts、未改shared-showcase.ts,不增加 boot 开销。用automation: true启动 showcase 需要process.chdir+ 三个 connector 插件 + 临时 MetadataPlugin(见showcase-declarative-endpoints.dogfood.test.ts),那是另一类测试;且在共享 stack 上做真能生效的DELETE /automation/:name断言,一旦门回归就会连带污染同 worker 的其他文件。顺带发现(未在本 PR 修)
@objectstack/core的ANONYMOUS_DENY_BODY注释写着 "The single 401 body shape every seam returns:{ error, message }",但 dispatcher 侧五个 seam(ai / meta / security / actions / automation)返回的是 wrapper 形状。已按 Prime Directive #10 单独立单,不在本 PR 修。🤖 Generated with Claude Code
https://claude.ai/code/session_016FNvXhtSdnEGEfLEsMmvxh
Generated by Claude Code