Clear the two forge reds main was carrying

56f2cadb0c5d · AtlantisPleb · · parent 574f15ebecc3

Clear the two forge reds main was carrying

Both were drift, and both are fixed on the drifting side rather than
by loosening a guard.

The exit rehearsal runbook named `rotate_github_tokens!/0` bare. The
guard resolves bare references against the modules the document names,
and no named module exported it — the function is
`OpenAgents.Accounts.rotate_github_tokens!/0`, so the runbook now says
so.

The #192 vault test asserted that rotating the GitHub key orphans a
machine pairing envelope. That was true when it was written and is not
true now: the machine vault has its own dedicated key and a
decrypt-side fallback to the GitHub keyring, and the documented
rotation moves the retired key into that keyring rather than deleting
it, so the envelope stays readable. The assertion is corrected to the
behavior the vault documents, with a comment saying why it changed.

The forge suite is green: 428 passed.

Built by a Devin child through the openagents coder's delegate tool;
the fallback was verified against the vault module's own contract
before the assertion was touched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GoYpb8FEmdxVErsv7ABCYi
Co-Authored-By
Claude Fable 5 <noreply@anthropic.com>

Deploy story

What this commit did to the running system — joined from the forge receipt chain, the part a commit page elsewhere cannot show.

pushed
by user · WAL seq 343 · 2026-08-25T05:36:29.373539Z

Changed files

  • modified docs/forge-exit-rehearsals.md
  • modified test/openagents/forge/key_rotation_test.exs

Diff

2 files changed, +13 -9

docs/forge-exit-rehearsals.md modified +3 -2

@@ -233,8 +233,9 @@ The forge holds several key-like secrets and they rotate differently:

233 233
  differ:
234 234
  - `OpenAgents.Accounts.TokenVault` (GitHub tokens) rotates without loss:
235 235
    the envelope names its key, the retired key joins
236
    `GITHUB_TOKEN_DECRYPTION_KEYS_JSON`, and `rotate_github_tokens!/0` rewraps
237
    every row under the active key.
236
    `GITHUB_TOKEN_DECRYPTION_KEYS_JSON`, and
237
    `OpenAgents.Accounts.rotate_github_tokens!/0` rewraps every row under the
238
    active key.
238 239
  - `OpenAgents.Machines.TokenVault` (pairing tokens,
239 240
    `MACHINE_TOKEN_ENCRYPTION_KEY`) rotates with bounded loss: at most one
240 241
    ten-minute window of unclaimed pairings becomes unreadable, and a person
test/openagents/forge/key_rotation_test.exs modified +10 -7

@@ -250,7 +250,7 @@ defmodule OpenAgents.Forge.KeyRotationTest do

250 250
      )
251 251
    end
252 252
253
    test "the machine pairing vault reads the GitHub vault's active key (#192)" do
253
    test "a GitHub key rotation does not orphan the machine pairing vault (#192)" do
254 254
      first = Base.encode64(:crypto.strong_rand_bytes(32))
255 255
      second = Base.encode64(:crypto.strong_rand_bytes(32))
256 256

@@ -261,11 +261,14 @@ defmodule OpenAgents.Forge.KeyRotationTest do

261 261
          sealed
262 262
        end)
263 263
264
      # Rotating the GitHub key — the documented procedure, performed in the
265
      # documented order — orphans this envelope, because the machine vault
266
      # carries no key id and consults no keyring. The blast radius is the ten
267
      # minutes of unclaimed pairings the lifetime allows, which is why this
268
      # is filed rather than treated as an incident.
264
      # The machine vault now has its own dedicated key
265
      # (`:machine_token_encryption_key`) and a decrypt-side fallback to the
266
      # GitHub keyring (#192, VAULT-001). A pairing record sealed under the
267
      # machine token key stays readable across a GitHub key rotation because
268
      # the rotation does not touch the machine vault's dedicated key. The
269
      # fallback covers historical records sealed while the runtime bridge
270
      # still mapped the machine key to the GitHub active key; the retired key
271
      # in `github_token_decryption_keys` opens those.
269 272
      with_env(
270 273
        [
271 274
          github_token_encryption_key: second,

@@ -273,7 +276,7 @@ defmodule OpenAgents.Forge.KeyRotationTest do

273 276
          github_token_decryption_keys: %{"first" => first}
274 277
        ],
275 278
        fn ->
276
          assert {:error, :token_unsealable} = MachineVault.open(sealed)
279
          assert {:ok, "smct_pairing"} = MachineVault.open(sealed)
277 280
        end
278 281
      )
279 282
    end

This page updates live while a promote is in flight · changelog