Grant SCV Codex slots to the fleet

9a31ce41e5b3 · AtlantisPleb · · parent 7160157a7a5f

Grant SCV Codex slots to the fleet

Deploy story

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

Not deployed through the forge lane

No push, promotion, build, or deploy receipt references this commit (receipts are scanned over a bounded recent window). Changes shipped by full node replacement carry their proof in the release gate receipt instead.

Changed files

  • modified docs/scv-codex-app-server-planning.md
  • modified docs/security/secrets-and-log-handling.md
  • modified infra/staging/main.tf
  • modified infra/staging/tests/safety.tftest.hcl
  • modified ops/staging/validate-isolation.sh
  • modified test/openagents/staging_candidate_contract_test.exs

Diff

6 files changed, +48 -7

docs/scv-codex-app-server-planning.md modified +3

@@ -683,6 +683,9 @@ incompatible account.

683 683
684 684
- Add restricted account and login-attempt records.
685 685
- Implement the device-code ceremony with one temporary process per attempt.
686
- Register each temporary process through the cluster registry so a LiveView
687
  reconnect on another fleet node can recover the same ceremony. Limit an
688
  unclustered web lane to one instance while the ceremony remains in memory.
686 689
- Add account read, model, rate-limit, health, drain, disconnect, and audit
687 690
  operations.
688 691
docs/security/secrets-and-log-handling.md modified +4 -4

@@ -11,8 +11,8 @@ more than one role on a node:

11 11
12 12
| Runtime identity | Purpose | May read |
13 13
| --- | --- | --- |
14
| `openagents-staging-web` | Phoenix release and forge Git endpoint | Web, provider, OAuth, vault, recording, forge verification, database, and cluster secrets listed below |
15
| `openagents-staging-fleet` | Three-node distributed application lane | The application secrets required by the same candidate plus the cluster cookie; no Compute mutation permission |
14
| `openagents-staging-web` | Phoenix release and forge Git endpoint | Web, provider, OAuth, vault, recording, forge verification, database, cluster, and preallocated Codex credential-slot secrets listed below |
15
| `openagents-staging-fleet` | Three-node distributed application lane | The application and preallocated Codex credential-slot secrets required by the same candidate plus the cluster cookie; no Compute mutation permission |
16 16
| `openagents-staging-deployer` | Minimal private rolling-replacement controller | Cluster cookie only; Compute mutation comes from its bounded workload identity |
17 17
| `openagents-staging-migrator` | Release migration and token rewrap job | Database URL, active GitHub vault key, prior GitHub vault keyring |
18 18
| `openagents-staging-builder` | Isolated BEAM build sidecar | Forge operator token only; use an askpass helper, never a URL or argv value |

@@ -39,8 +39,8 @@ use distinct names and values and remains locked.

39 39
| `VOICE_RECORDING_ENCRYPTION_KEY` | `openagents-staging-voice-recording-key` | web and fleet when recording is admitted | Scheduled recording-key procedure or suspected exposure |
40 40
| `OPENAGENTS_FORGE_OPERATOR_TOKEN` | `openagents-staging-forge-operator-token` | web, fleet, builder | Scheduled rotation, builder replacement, or suspected URL/argv/log exposure |
41 41
| `RELEASE_COOKIE` | `openagents-staging-release-cookie` | web, fleet, deployer | Fleet-wide coordinated rotation or suspected exposure |
42
| Connected Codex account slot 1 | `openagents-staging-scv-codex-operator-1` | web may add and read versions; a future isolated Codex SCV runtime may read one exact version | Operator disconnect, OpenAI reauthentication, or suspected exposure |
43
| Connected Codex account slot 2 | `openagents-staging-scv-codex-operator-2` | web may add and read versions; a future isolated Codex SCV runtime may read one exact version | Operator disconnect, OpenAI reauthentication, or suspected exposure |
42
| Connected Codex account slot 1 | `openagents-staging-scv-codex-operator-1` | web and fleet may add and read versions; an isolated Codex SCV runtime may read one exact version | Operator disconnect, OpenAI reauthentication, or suspected exposure |
43
| Connected Codex account slot 2 | `openagents-staging-scv-codex-operator-2` | web and fleet may add and read versions; an isolated Codex SCV runtime may read one exact version | Operator disconnect, OpenAI reauthentication, or suspected exposure |
44 44
45 45
`GITHUB_CLIENT_ID` and `GITHUB_TOKEN_ENCRYPTION_KEY_ID` are identifiers, not
46 46
secrets. `DB_PASSWORD` is not used by the admitted staging profile because it
infra/staging/main.tf modified +16

@@ -391,6 +391,22 @@ resource "google_secret_manager_secret_iam_member" "scv_codex_credential_read" {

391 391
  member    = google_service_account.web.member
392 392
}
393 393
394
resource "google_secret_manager_secret_iam_member" "fleet_scv_codex_credential_add" {
395
  for_each = local.scv_codex_credential_secrets
396
397
  secret_id = google_secret_manager_secret.runtime[each.value].id
398
  role      = "roles/secretmanager.secretVersionAdder"
399
  member    = google_service_account.fleet.member
400
}
401
402
resource "google_secret_manager_secret_iam_member" "fleet_scv_codex_credential_read" {
403
  for_each = local.scv_codex_credential_secrets
404
405
  secret_id = google_secret_manager_secret.runtime[each.value].id
406
  role      = "roles/secretmanager.secretAccessor"
407
  member    = google_service_account.fleet.member
408
}
409
394 410
resource "google_artifact_registry_repository" "openagents" {
395 411
  location      = var.region
396 412
  repository_id = "openagents-staging"
infra/staging/tests/safety.tftest.hcl modified +16

@@ -73,6 +73,22 @@ run "isolated_topology" {

73 73
    error_message = "The staging web identity may read exact versions only from the preallocated SCV Codex credential slots."
74 74
  }
75 75
76
  assert {
77
    condition = alltrue([
78
      for binding in values(google_secret_manager_secret_iam_member.fleet_scv_codex_credential_add) :
79
      binding.role == "roles/secretmanager.secretVersionAdder"
80
    ])
81
    error_message = "The staging fleet identity may add versions only to the preallocated SCV Codex credential slots."
82
  }
83
84
  assert {
85
    condition = alltrue([
86
      for binding in values(google_secret_manager_secret_iam_member.fleet_scv_codex_credential_read) :
87
      binding.role == "roles/secretmanager.secretAccessor"
88
    ])
89
    error_message = "The staging fleet identity may read exact versions only from the preallocated SCV Codex credential slots."
90
  }
91
76 92
  assert {
77 93
    condition = toset(google_project_iam_custom_role.deployer.permissions) == toset([
78 94
      "compute.instances.get",
ops/staging/validate-isolation.sh modified +6 -3

@@ -132,11 +132,14 @@ jq -e '

132 132
' "$run_root/secrets.json" >/dev/null
133 133
134 134
web_member="serviceAccount:openagents-staging-web@$staging_project.iam.gserviceaccount.com"
135
fleet_member="serviceAccount:openagents-staging-fleet@$staging_project.iam.gserviceaccount.com"
135 136
136 137
for slot in openagents-staging-scv-codex-operator-1 openagents-staging-scv-codex-operator-2; do
137
  jq -e --arg member "$web_member" '
138
    any(.bindings[]?; .role == "roles/secretmanager.secretVersionAdder" and (.members | index($member))) and
139
    any(.bindings[]?; .role == "roles/secretmanager.secretAccessor" and (.members | index($member)))
138
  jq -e --arg web "$web_member" --arg fleet "$fleet_member" '
139
    all([$web, $fleet][]; . as $member |
140
      any(.bindings[]?; .role == "roles/secretmanager.secretVersionAdder" and (.members | index($member))) and
141
      any(.bindings[]?; .role == "roles/secretmanager.secretAccessor" and (.members | index($member)))
142
    )
140 143
  ' "$run_root/$slot-iam.json" >/dev/null
141 144
done
142 145
test/openagents/staging_candidate_contract_test.exs modified +3

@@ -81,7 +81,10 @@ defmodule OpenAgents.StagingCandidateContractTest do

81 81
82 82
    assert terraform =~ "roles/secretmanager.secretVersionAdder"
83 83
    assert terraform =~ "roles/secretmanager.secretAccessor"
84
    assert terraform =~ "fleet_scv_codex_credential_add"
85
    assert terraform =~ "fleet_scv_codex_credential_read"
84 86
    assert isolation_validator =~ "scv_codex_credential_slots"
87
    assert isolation_validator =~ "fleet_member"
85 88
  end
86 89
87 90
  test "production preflight preserves a pinned candidate across later commits" do

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