Provision SCV Codex credential slots

197b6f8e2887 · AtlantisPleb · · parent 29326806f9c3

Provision SCV Codex credential slots

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 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

4 files changed, +75 -2

infra/staging/main.tf modified +24 -1

@@ -38,7 +38,14 @@ locals {

38 38
    "openagents-staging-openai-api-key",
39 39
    "openagents-staging-voice-recording-key",
40 40
    "openagents-staging-forge-operator-token",
41
    "openagents-staging-release-cookie"
41
    "openagents-staging-release-cookie",
42
    "openagents-staging-scv-codex-operator-1",
43
    "openagents-staging-scv-codex-operator-2"
44
  ])
45
46
  scv_codex_credential_secrets = toset([
47
    "openagents-staging-scv-codex-operator-1",
48
    "openagents-staging-scv-codex-operator-2"
42 49
  ])
43 50
44 51
  application_secrets = toset([

@@ -368,6 +375,22 @@ resource "google_secret_manager_secret_iam_member" "deployer_cookie" {

368 375
  member    = google_service_account.deployer.member
369 376
}
370 377
378
resource "google_secret_manager_secret_iam_member" "scv_codex_credential_add" {
379
  for_each = local.scv_codex_credential_secrets
380
381
  secret_id = google_secret_manager_secret.runtime[each.value].id
382
  role      = "roles/secretmanager.secretVersionAdder"
383
  member    = google_service_account.web.member
384
}
385
386
resource "google_secret_manager_secret_iam_member" "scv_codex_credential_read" {
387
  for_each = local.scv_codex_credential_secrets
388
389
  secret_id = google_secret_manager_secret.runtime[each.value].id
390
  role      = "roles/secretmanager.secretAccessor"
391
  member    = google_service_account.web.member
392
}
393
371 394
resource "google_artifact_registry_repository" "openagents" {
372 395
  location      = var.region
373 396
  repository_id = "openagents-staging"
infra/staging/tests/safety.tftest.hcl modified +17 -1

@@ -53,10 +53,26 @@ run "isolated_topology" {

53 53
  }
54 54
55 55
  assert {
56
    condition     = length(google_secret_manager_secret.runtime) == 13
56
    condition     = length(google_secret_manager_secret.runtime) == 15
57 57
    error_message = "Every named staging credential and lane configuration needs its own secret resource."
58 58
  }
59 59
60
  assert {
61
    condition = alltrue([
62
      for binding in values(google_secret_manager_secret_iam_member.scv_codex_credential_add) :
63
      binding.role == "roles/secretmanager.secretVersionAdder"
64
    ])
65
    error_message = "The staging web identity may add versions only to the preallocated SCV Codex credential slots."
66
  }
67
68
  assert {
69
    condition = alltrue([
70
      for binding in values(google_secret_manager_secret_iam_member.scv_codex_credential_read) :
71
      binding.role == "roles/secretmanager.secretAccessor"
72
    ])
73
    error_message = "The staging web identity may read exact versions only from the preallocated SCV Codex credential slots."
74
  }
75
60 76
  assert {
61 77
    condition = toset(google_project_iam_custom_role.deployer.permissions) == toset([
62 78
      "compute.instances.get",
ops/staging/validate-isolation.sh modified +17

@@ -57,6 +57,11 @@ gcloud compute networks list --project="$staging_project" --format=json >"$run_r

57 57
gcloud projects get-iam-policy "$staging_project" --format=json >"$run_root/staging-iam.json"
58 58
gcloud iam service-accounts list --project="$production_project" --format=json >"$run_root/production-accounts.json"
59 59
60
for slot in openagents-staging-scv-codex-operator-1 openagents-staging-scv-codex-operator-2; do
61
  gcloud secrets get-iam-policy "$slot" --project="$staging_project" --format=json \
62
    >"$run_root/$slot-iam.json"
63
done
64
60 65
jq -e '
61 66
  length == 1 and
62 67
  .[0].name == "openagents-staging-postgres" and

@@ -118,12 +123,23 @@ jq -e '

118 123
    "openagents-staging-github-vault-previous",
119 124
    "openagents-staging-openai-api-key",
120 125
    "openagents-staging-release-cookie",
126
    "openagents-staging-scv-codex-operator-1",
127
    "openagents-staging-scv-codex-operator-2",
121 128
    "openagents-staging-secret-key-base",
122 129
    "openagents-staging-voice-recording-key",
123 130
    "openagents-staging-web-config"
124 131
  ][]; . as $required | $names | index($required))
125 132
' "$run_root/secrets.json" >/dev/null
126 133
134
web_member="serviceAccount:openagents-staging-web@$staging_project.iam.gserviceaccount.com"
135
136
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)))
140
  ' "$run_root/$slot-iam.json" >/dev/null
141
done
142
127 143
jq -e '
128 144
  [.[].email | split("@") | first] as $names |
129 145
  all([

@@ -168,6 +184,7 @@ jq -n \

168 184
      three_private_fleet_nodes: "passed",
169 185
      staging_buckets: "passed",
170 186
      staging_secrets: "passed",
187
      scv_codex_credential_slots: "passed",
171 188
      split_service_accounts: "passed",
172 189
      private_dns_and_network: "passed",
173 190
      no_production_service_accounts: "passed"
test/openagents/staging_candidate_contract_test.exs modified +17

@@ -67,6 +67,23 @@ defmodule OpenAgents.StagingCandidateContractTest do

67 67
             ~s(target_tags   = ["openagents-staging-fleet", "openagents-staging-controller"])
68 68
  end
69 69
70
  test "SCV Codex credentials use preallocated least-privilege staging slots" do
71
    terraform = File.read!("infra/staging/main.tf")
72
    isolation_validator = File.read!("ops/staging/validate-isolation.sh")
73
74
    for slot <- [
75
          "openagents-staging-scv-codex-operator-1",
76
          "openagents-staging-scv-codex-operator-2"
77
        ] do
78
      assert terraform =~ slot
79
      assert isolation_validator =~ slot
80
    end
81
82
    assert terraform =~ "roles/secretmanager.secretVersionAdder"
83
    assert terraform =~ "roles/secretmanager.secretAccessor"
84
    assert isolation_validator =~ "scv_codex_credential_slots"
85
  end
86
70 87
  test "production preflight preserves a pinned candidate across later commits" do
71 88
    preflight = File.read!("ops/production/preflight.sh")
72 89

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