Skip to content

feat: shared backend on Cloud Run with a workshop password - #1

Merged
Statyk7 merged 6 commits into
mainfrom
preparing-for-shared-server
Oct 29, 2026
Merged

Statyk7 merged 6 commits into
mainfrom
preparing-for-shared-server

Conversation

@pietroid

@pietroid pietroid commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator
  • Shared backend: runtime/ deploys to Cloud Run (deploy_runtime workflow, Workload Identity, no key file); PRs typecheck it, test the password gate and build the image (runtime_ci). The key and the password live in Secret Manager, and a manual warm_runtime workflow keeps the service awake before an event.
  • Password: the app sends X-Workshop-Code and a random X-Workshop-Session on every run (--dart-define=WORKSHOP_CODE); the runtime checks the code only when WORKSHOP_CODE is set, so local runtimes are unchanged. /info and the CORS preflight stay open. The gate (runtime/gate.ts) logs each run with its session id and caps runs per session and in total (MAX_RUNS_PER_SESSION, MAX_RUNS_TOTAL).
  • tool/setup.mjs and tool/doctor.mjs check the password up front with an empty run, and only ask for it when the backend needs one; tool/workshop.config.json points at the shared backend.
  • The model key is ANTHROPIC_API_KEY everywhere.
  • One-time Google Cloud setup: runtime/deploy/setup_gcp.sh (secrets, deployer role, public access). Run it again after the first deploy.

Before merging, add two repo secrets: GCP_WORKLOAD_IDENTITY_PROVIDER and GCP_SERVICE_ACCOUNT. The old CLAUDE_API_KEY, ANTHROPIC_API_KEY and WORKSHOP_CODE repo secrets are not used.

Tested: the deployed service (401 without the code, streamed model runs, doctor.mjs), the gate tests, and step 02 in Chrome. Secret Manager and the deployer role are set up in the project, but the workflows themselves have not run yet, and neither have the Flutter tests.

- runtime/Dockerfile and ignore files: the image holds only server.ts and
  env.ts, and a source deploy uploads nothing else (no .env)
- deploy_runtime workflow: builds the image, deploys to Cloud Run through
  Workload Identity and checks that the password gate is on
- runtime_ci workflow: typechecks the runtime and builds the image on pull
  requests
- runtime/deploy: one-time Google Cloud setup script and the steps
- point tool/workshop.config.json at the deployed backend
- the runtime, the step 03 server, setup and doctor read CLAUDE_API_KEY and
  hand it to the Anthropic SDK as ANTHROPIC_API_KEY
- the deploy workflow passes the CLAUDE_API_KEY repository secret to Cloud Run
- update the examples, the README and the deploy steps

@Statyk7 Statyk7 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this Pietro, the design is solid: Workload Identity with no key file and a repo + main condition, a runtime service account with no roles, .env kept out of the image, a smoke test that asserts the 401, a constant-time comparison, and local runtimes unchanged.

Tested on this branch: runtime typecheck passes; Flutter analyze and app tests pass in steps 01 to 03; password gate on a local copy (/info 200 without a code, run without or with a wrong code 401, right code passes, stop without a code 401, preflight 204); runtime_ci passes; the deployed /info answers 200 with CORS open.
Not tested: the deploy workflow itself (needs the secrets and only runs on main), Safari or Firefox, Windows.

Before merging (details inline):

  1. setup.mjs can print the password in clear.
  2. Cold start versus the doctor's 8 second timeout.
  3. The CLAUDE_API_KEY rename breaks existing ANTHROPIC_API_KEY setups.

Suggestions: spend caps and using the session header, deployer permissions and pinned actions, tests for the gate, checking the password in setup, and the README's PowerShell command. The PR description also still mentions runtime/deploy/README.md, which the last commit removed.

Happy to send a follow-up with these if that helps.

Comment thread tool/setup.mjs Outdated
Comment thread tool/setup.mjs Outdated
Comment thread runtime/env.ts Outdated
Comment thread runtime/server.ts Outdated
Comment thread runtime/server.ts Outdated
Comment thread .github/workflows/deploy_runtime.yaml
Comment thread .github/workflows/deploy_runtime.yaml Outdated
Comment thread .github/workflows/deploy_runtime.yaml Outdated
Comment thread runtime/deploy/setup_gcp.sh Outdated
Comment thread README.md Outdated
- key: name it ANTHROPIC_API_KEY everywhere again
- gate: move the password gate to runtime/gate.ts, log and cap runs per
  session and in total, and test it with node:test in runtime_ci
- setup, doctor: mask the password by argument, check it up front with an
  empty run, wait longer for a cold hosted backend
- deploy: keep the key and password in Secret Manager, give the deployer
  run.developer and make the service public from setup_gcp.sh, use
  --cpu-boost, add a warm_runtime workflow
- actions: pin to commit SHAs and add Dependabot
- docs: one-line flutter run, note that a build made with the password
  contains it
@Statyk7
Statyk7 merged commit 9e2eff8 into main Oct 29, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants