row 281 design d3: a grant decision approved before a fire and executed after it, tests T6/T6b/T6c (sage-2574, #1786)

This commit is contained in:
jason.woltje committed 2026-10-22 04:58:09 -05:00
1 parent c746ce378c
commit 36c2d98b81
1 file changed
+18 -5
+18 -5
View File
@@ -1,7 +1,7 @@
# Row 281 build notes: a fire or a delete revokes the instance's grants (#1786)
Builder Megavolt, reviewer Dewey, gate owner Sage. Design draft d2 for Dewey's approval. d2 adds Sage's
Q1/Q2 rulings (sage-2573) to d1 (dfebd16cc). No code until it is
Builder Megavolt, reviewer Dewey, gate owner Sage. Design draft d3 for Dewey's approval. d2 added Sage's
Q1/Q2 rulings (sage-2573) to d1 (dfebd16cc). d3 adds the approved-before-fire tests T6/T6b/T6c (sage-2574). No code until it is
approved. The results sections are filled in after the runs on Sage's gate.
## Sources
@@ -136,6 +136,13 @@ A host named only by an open decision has no record. Step 3a still runs `remove`
`#revokedSince` then ends that decision `revoked`. The Gitea side is the same through
`#giteaRevokedSince`.
This is the case where a decision is approved before the fire and executed after it (sage-2574). Both checks
look for a `grant.revoked` of the agent recorded after the decision was raised (broker.mjs:1156 and :1678 at
47a35bf43). A fire's `grant.revoked` is always later than the approval, so the executor ends the decision
whenever it runs. The fired agent keeps its roles entry, so `#hostDefinition` and `#giteaRole` still pass, and
this check is the only thing that stops the decision. T6 and T6b test it. A delete also removes the roles
entry, so the executor refuses there as well.
## 4. A refusal (D4)
Step G stops at the first grant that can't be revoked. Grants already revoked in this step G stay revoked and
@@ -221,8 +228,14 @@ Bus, with the fake installer and the fake Gitea the row 235 and 236 tests use:
unrevoked. A repeat with B reachable completes and revokes only B and Gitea.
- T5: Gitea's admin token can't be checked. The fire refuses with the Gitea grant intact.
- T5b: a token DELETE fails. The fire refuses `gitea-left`. A repeat with Gitea back sweeps and completes.
- T6: an approved host grant decision that hasn't run yet, for the fired agent: the fire records
`grant.revoked {granted: false}`, and the executor then ends that decision `revoked`.
- T6 (sage-2574): a host grant decision approved before the fire, executed after it. The fire records
`grant.revoked {granted: false}` for (agent, host). The executor runs after `fire.done` and ends the decision
`revoked`: no `host_grants` row, no key file, no `add` sent to the host.
- T6b (sage-2574): the same for a Gitea grant decision. The executor ends it `revoked` before any Gitea call:
no `gitea_grants` row, no token file, and the fake Gitea saw no token create.
- T6c: a host or Gitea executor already in flight when step G starts. The host side aborts its claim (step
3a.1) and ends `revoked`. The Gitea side ends `revoked` at its step 8 check. Build-time check: a token the
in-flight executor created before that check must be deleted, or named in `serviceLeft`, and not left live.
- T7: an instance with no grant fires exactly as today. Same result keys, and the same events, counted.
- T8: hosts.revoke and grants.revoke keep their records, their order and their tester refusals.
@@ -237,7 +250,7 @@ G closes the request with `grant-revoke-failed`, if the launcher's tests stub `l
- M4: `lifecycleDelete` skips step G. Killed by T3.
- M5: the fire's host revoke goes local first (`lineFirst: false`). Killed by T4, because B's row is gone.
- M6: a Gitea revoke with something in `serviceLeft` counts as done. Killed by T5b.
- M7: open decisions left out of the set. Killed by T6.
- M7: open decisions left out of the set. Killed by T6 and T6b.
- M8: step G skips the leftover-line retry. Killed by T4b.
- M9: a failed leftover-line retry refuses the fire. Killed by T4b.