Connect staging fleet through Cloud SQL Auth Proxy

f088bb7d9f33 · AtlantisPleb · · parent 80041b159b44

Connect staging fleet through Cloud SQL Auth Proxy

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 Dockerfile
  • modified config/runtime.exs
  • modified docs/runtime-configuration.md
  • modified infra/staging/README.md
  • modified infra/staging/main.tf
  • modified infra/staging/templates/fleet-startup.sh.tftpl
  • modified infra/staging/tests/safety.tftest.hcl
  • modified ops/staging/validate-isolation.sh
  • modified test/openagents/staging_candidate_contract_test.exs

Diff

9 files changed, +65 -3

Dockerfile modified +1

@@ -104,6 +104,7 @@ FROM builder AS forge-builder

104 104
105 105
COPY ops/forge ops/forge
106 106
107
ENV OPENAGENTS_RUNTIME_ROLE=builder
107 108
CMD ["mix", "run", "--no-compile", "--no-start", "ops/forge/build-worker.exs"]
108 109
109 110
# start a new build stage so that the final image will only contain
config/runtime.exs modified +1

@@ -86,6 +86,7 @@ runtime_role =

86 86
  case System.get_env("OPENAGENTS_RUNTIME_ROLE", "web") do
87 87
    "web" -> :web
88 88
    "scv" -> :scv
89
    "builder" -> :builder
89 90
    _invalid -> raise "environment variable OPENAGENTS_RUNTIME_ROLE is not admitted"
90 91
  end
91 92
docs/runtime-configuration.md modified +1

@@ -50,6 +50,7 @@ The setting accepts these values:

50 50
| --- | --- |
51 51
| `web` | Default. Validates the complete web release configuration and starts the endpoint, Repo, Forge, and enabled application services. |
52 52
| `scv` | Staging-only qualification role. Requires a provider credential and starts one temporary `OpenAgents.SCV.Worker` task. It starts no endpoint, Repo, Forge service, or deployment coordinator. |
53
| `builder` | Isolated Forge build-image role. Loads compiled modules for the queue worker without starting the application, endpoint, Repo, or deployment coordinator. |
53 54
54 55
The current SCV process role admits only the `opencode` driver,
55 56
`opencode-core` environment, and `read_only` permission profile. Configure one
infra/staging/README.md modified +4

@@ -24,6 +24,10 @@ The configuration creates these staging-only resources:

24 24
  builder lanes, plus one Secret Manager resource per credential in the
25 25
  staging secret inventory. The deployer can read only the release cookie.
26 26
  Terraform never creates a secret version or stores a credential in state.
27
- Separate database URL secrets for the Cloud Run web lane and private Compute
28
  Engine fleet. The web URL selects the managed Cloud SQL Unix socket. The
29
  fleet URL selects a loopback TCP listener provided by a digest-pinned Cloud
30
  SQL Auth Proxy, which uses private IP and encrypted PostgreSQL transport.
27 31
- Separate buckets for forge artifacts, forge WAL, recordings, and evidence.
28 32
- One Artifact Registry repository for digest-addressed application and builder
29 33
  images. Full-SHA tags are immutable, and Terraform cannot delete the
infra/staging/main.tf modified +13 -1

@@ -30,6 +30,7 @@ locals {

30 30
    "openagents-staging-fleet-config",
31 31
    "openagents-staging-builder-config",
32 32
    "openagents-staging-database-url",
33
    "openagents-staging-fleet-database-url",
33 34
    "openagents-staging-secret-key-base",
34 35
    "openagents-staging-github-client-secret",
35 36
    "openagents-staging-github-vault-active",

@@ -41,7 +42,6 @@ locals {

41 42
  ])
42 43
43 44
  application_secrets = toset([
44
    "openagents-staging-database-url",
45 45
    "openagents-staging-secret-key-base",
46 46
    "openagents-staging-github-client-secret",
47 47
    "openagents-staging-github-vault-active",

@@ -322,12 +322,24 @@ resource "google_secret_manager_secret_iam_member" "web_env" {

322 322
  member    = google_service_account.web.member
323 323
}
324 324
325
resource "google_secret_manager_secret_iam_member" "web_database" {
326
  secret_id = google_secret_manager_secret.runtime["openagents-staging-database-url"].id
327
  role      = "roles/secretmanager.secretAccessor"
328
  member    = google_service_account.web.member
329
}
330
325 331
resource "google_secret_manager_secret_iam_member" "fleet_env" {
326 332
  secret_id = google_secret_manager_secret.runtime["openagents-staging-fleet-config"].id
327 333
  role      = "roles/secretmanager.secretAccessor"
328 334
  member    = google_service_account.fleet.member
329 335
}
330 336
337
resource "google_secret_manager_secret_iam_member" "fleet_database" {
338
  secret_id = google_secret_manager_secret.runtime["openagents-staging-fleet-database-url"].id
339
  role      = "roles/secretmanager.secretAccessor"
340
  member    = google_service_account.fleet.member
341
}
342
331 343
resource "google_secret_manager_secret_iam_member" "builder_env" {
332 344
  secret_id = google_secret_manager_secret.runtime["openagents-staging-builder-config"].id
333 345
  role      = "roles/secretmanager.secretAccessor"
infra/staging/templates/fleet-startup.sh.tftpl modified +33 -1

@@ -30,6 +30,7 @@ mkdir -p \

30 30
  "$state_root/ra" \
31 31
  "$state_root/workspace/build" \
32 32
  "$state_root/workspace/build-queue"
33
chown -R 65534:65534 "$state_root"
33 34
34 35
image=$(metadata_attribute openagents-image)
35 36
image_digest=$(metadata_attribute openagents-image-digest)

@@ -122,7 +123,7 @@ if grep -Eq '^(DATABASE_URL|SECRET_KEY_BASE|GITHUB_CLIENT_SECRET|GITHUB_TOKEN_EN

122 123
  exit 1
123 124
fi
124 125
125
append_secret DATABASE_URL openagents-staging-database-url /run/openagents/runtime.env
126
append_secret DATABASE_URL openagents-staging-fleet-database-url /run/openagents/runtime.env
126 127
append_secret SECRET_KEY_BASE openagents-staging-secret-key-base /run/openagents/runtime.env
127 128
append_secret GITHUB_CLIENT_SECRET openagents-staging-github-client-secret /run/openagents/runtime.env
128 129
append_secret GITHUB_TOKEN_ENCRYPTION_KEY openagents-staging-github-vault-active /run/openagents/runtime.env

@@ -143,6 +144,37 @@ export DOCKER_CONFIG=/run/openagents/docker-config

143 144
mkdir -p "$DOCKER_CONFIG"
144 145
chmod 0700 "$DOCKER_CONFIG"
145 146
docker-credential-gcr configure-docker --registries=${region}-docker.pkg.dev
147
148
cloud_sql_proxy_image=gcr.io/cloud-sql-connectors/cloud-sql-proxy@sha256:825d5e4ce70d38bd0006c9eea15a6a2e2983e87b31ac6924d33e2dba56eafc9f
149
docker pull "$cloud_sql_proxy_image"
150
docker rm --force openagents-cloud-sql-proxy 2>/dev/null || true
151
docker run --detach \
152
  --name openagents-cloud-sql-proxy \
153
  --network host \
154
  --restart always \
155
  "$cloud_sql_proxy_image" \
156
  --address 127.0.0.1 \
157
  --health-check \
158
  --http-address 127.0.0.1 \
159
  --http-port 9090 \
160
  --port 5432 \
161
  --private-ip \
162
  "${project_id}:${region}:openagents-staging-postgres"
163
164
proxy_ready=false
165
for _attempt in $(seq 1 60); do
166
  if curl --fail --silent http://127.0.0.1:9090/readiness >/dev/null; then
167
    proxy_ready=true
168
    break
169
  fi
170
  sleep 1
171
done
172
173
if [ "$proxy_ready" != true ]; then
174
  echo "Cloud SQL Auth Proxy did not become ready" >&2
175
  exit 1
176
fi
177
146 178
docker pull "$image"
147 179
docker rm --force openagents 2>/dev/null || true
148 180
docker run --detach \
infra/staging/tests/safety.tftest.hcl modified +1 -1

@@ -53,7 +53,7 @@ run "isolated_topology" {

53 53
  }
54 54
55 55
  assert {
56
    condition     = length(google_secret_manager_secret.runtime) == 12
56
    condition     = length(google_secret_manager_secret.runtime) == 13
57 57
    error_message = "Every named staging credential and lane configuration needs its own secret resource."
58 58
  }
59 59
ops/staging/validate-isolation.sh modified +1

@@ -110,6 +110,7 @@ jq -e '

110 110
  all([
111 111
    "openagents-staging-builder-config",
112 112
    "openagents-staging-database-url",
113
    "openagents-staging-fleet-database-url",
113 114
    "openagents-staging-fleet-config",
114 115
    "openagents-staging-forge-operator-token",
115 116
    "openagents-staging-github-client-secret",
test/openagents/staging_candidate_contract_test.exs modified +10

@@ -34,6 +34,16 @@ defmodule OpenAgents.StagingCandidateContractTest do

34 34
             ~s(RELEASE_COOKIE:?RELEASE_COOKIE is required for a distributed node)
35 35
  end
36 36
37
  test "the isolated builder loads runtime configuration without the web role" do
38
    dockerfile = File.read!("Dockerfile")
39
    runtime_config = File.read!("config/runtime.exs")
40
41
    assert dockerfile =~ "FROM builder AS forge-builder"
42
    assert dockerfile =~ "ENV OPENAGENTS_RUNTIME_ROLE=builder"
43
    assert dockerfile =~ ~s(mix", "run", "--no-compile", "--no-start")
44
    assert runtime_config =~ ~s("builder" -> :builder)
45
  end
46
37 47
  test "candidate publication binds exact immutable registry and artifact identities" do
38 48
    publisher = File.read!("ops/staging/publish-candidate.sh")
39 49
    sbom = File.read!("ops/staging/generate-sbom.sh")

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