Repository navigation
policy-sign does not cover the risk-tier data: risk-rules.json and its test can change without a human signature - #3092
Conversation
…iles risk-gate.mjs was a gate file while the rules it reads and the test that pins where each pattern applies were not, so a pull request could rewrite the tier every later pull request gets with no human signature. policy/ stays a directory entry; the two files are added individually.
|
@Birfy verdict request — tip What it changes: Why: Red first ×2 at Checks at this tip: Correction to this comment's first line: the computed tier is T2, not T3 — |
Fixes #3091
Owner: Dev-1
Reviewer: Birfy
Written-by: Dev-1
Bot: FlyBot Dev-1
Claim-Id: da93569a1a5948fbb832b05330c7d0cb
Tier: T2 (
policy/is not a T3 path, so both files fall to the unknown-path default;policy-signapplies because this PR edits agateFile, not because of the tier)Base: 3e901fa
Verified commit: 9475ca45976ae6ac0ec72b7f5e781df1931cf1c4
Tree: 421f0618619752e4e021e42edee456a7dde35450
Pushed head: e19cb05
What was wrong
policy/gates.jsonlisted the tier checker.github/scripts/risk-gate.mjs, but not the data it reads and not the test that pins where each pattern applies. So.github/agent/risk-rules.json— the file that decides what counts as T3 for every later pull request in this repository — could be rewritten by a pull request that carries no human signature, and.github/scripts/risk-gate.test.mjscould lose the pin that keeps each pattern on the right side of the test boundary.#3089is the live example: it movednew Function\(and\beval\(between the two lists, which changes the tier every future pull request is given, and it landed on3e901fabat 2026-11-15T00:47:11Z withpolicy-signgreen, becausegateFiles()returned[]for its two files. The change was right; the signature surface simply did not cover it.The change
Two entries in
policy/gates.jsongateFiles:.github/agent/risk-rules.json.github/scripts/risk-gate.test.mjsNothing else:
policy/is already a directory entry (sopolicy/gates.jsoncannot change unsigned — this change included), no other file class is added,policy-sign.mjs,risk-gate.mjsandrisk-rules.jsonthemselves are untouched, and the list is not reordered.Red first, at
3e901fab, twiceFour cases added to
policy/gates.test.mjswithpolicy/gates.jsonuntouched:node --test policy/gates.test.mjs→ 7 tests, 4 pass, 3 fail, exit 1, both runs. The three failures are the acceptance cases, the fourth (the controls) passes on purpose:red-1.logsha2564a63c0e1f7034120,red-2.logsha2569bf83f2867e48f77.The cases ask the checker itself —
gateFiles()andjudge()imported from.github/scripts/policy-sign.mjs— rather than re-readingpolicy.gateFilesin the test: a second reading could agree with the list while disagreeing with the gate the workflow runs. Case 6 drivesjudge()to end to end: the tier-data change with a body carrying noPolicy-sign:line is refused with a reason namingrisk-rules.jsonand the missing line, and the same change withPolicy-sign: 4242naming a signable comment is accepted.Green after, twice
Same command with the two entries added → 7 tests, 7 pass, 0 fail, exit 0, both runs (
green-final-1.logsha25631a8be21908962b9,green-final-2.logsha256902de10ef78277e4).The control case stayed green through both runs:
.github/scripts/risk-gate.mjsis still a gate change, and an ordinary client file (plugins/social/client.js) is not.What this does to the queue
This pull request changes
policy/gates.json, which is itself a gate file, so its ownpolicy-signwill be red until a person writesPolicy-sign: <comment id>into this body, naming a comment by someone other than the author that also names this tip. That is the intended shape — the owner keeps the veto on widening the signature surface — and a bot account cannot sign, so this body carries no such line.enqueue-guardwill be red for the usualno Verifier report names the tip.Gates, at
9475ca45(tree421f0618)TZ=UTC npm run verify→ exit 0: core 3248, social 684, tree 149, timeline 172, workflow 535, project 147, gate/policy 685, interop 37, live-e2e 34 — 0 fail everywhere (sha256of the log744fb5e903ffdb03).Also run on this tree:
cd core && ARCH_DOCS_BASE=3e901fab… node scripts/check-arch-docs.mjs—arch-docs: OK (2 changed file(s));node .github/scripts/changelog.mjs check— 1 fragment well formed;node .github/scripts/testing-layers.mjs --check— every test file and every workflow classified;node .github/scripts/check-mojibake.mjs --check— 0 occurrences of U+FFFD in 1705 text files.Files
2 files,
+39/−0:policy/gates.json(+2) — the twogateFilesentriespolicy/gates.test.mjs(+37) — the four casesCheckpoint
{ "pr": 3092, "claim": "Dev-1", "issue": 3091, "summary": "policy/gates.json listed the tier checker but not the risk-tier data it reads, so a pull request could rewrite the file that decides what counts as T3 for every later pull request with no human signature. risk-rules.json and risk-gate.test.mjs are now gate files; policy/ stays a directory entry and nothing else is added. The four cases ask the checker itself through gateFiles() and judge(), so they cannot agree with the list while disagreeing with the workflow. One case is a control on purpose: the tier checker is still a gate file and an ordinary client file is not.", "files": [ "policy/gates.json", "policy/gates.test.mjs" ], "checks": { "ran": "TZ=UTC npm run verify; node --test policy/gates.test.mjs (red x2 before, green x2 after); arch-docs, changelog, testing-layers, check-mojibake", "result": "green", "at": "e19cb051888267b5e91f00ffcab13250a1df862a" }, "next": "a human Policy-sign on this body after a Verdict; the signature line is not mine to write" }