docs(deploy): make the deployment docs describe the container deploy - #497
docs(deploy): make the deployment docs describe the container deploy#497frankbria wants to merge 2 commits into
Conversation
Staging moved to containers on 2026-08-12 (#484), but four documents still told you the GitHub secrets are how application config reaches the box. They don't: deploy-staging-containers.yml ships the compose files and runs `docker compose up`, and every application secret is read from /opt/auto-author/.env, which no workflow writes. Following the docs meant editing something with no effect on what runs. - docs/GITHUB_SECRETS_SETUP.md: deleted. It framed MONGODB_URI and DATABASE_NAME as E2E-test secrets; e2e-staging-tests.yml references neither. - docs/STAGING-DEPLOYMENT.md: 791 -> 195 lines. The bulk described a machine this project no longer uses -- `frankbria-inspiron-7586`, PostgreSQL 14, `psql`/`VACUUM ANALYZE`, /home/frankbria/staging paths -- for a MongoDB app on a shared VPS. Kept and updated the two true parts (network exposure #189, now describing the compose loopback bindings rather than PM2 flags; the container-deploy section), and rewrote around them. - docs/DATABASE_CONNECTION_STANDARD.md: the standard itself is still true and still enforced (base.py:33, auth.ts:156), so it stays. Replaced the dead secret -> DATABASE_URL plumbing with the .env/compose reality, and added the reason the rule exists: a db name in the path becomes defaultauthdb, which authSource defaults to, so it breaks Atlas auth -- and is ignored anyway. Adds password-escaping rules and a rotation runbook. - .github/DEPLOYMENT.md: added a which-workflow-reads-what table and the Tailscale secrets the live deploy actually uses; marked the PM2 env-file layout as the retired path. - CLAUDE.md, deploy-staging-containers.yml header: both still called staging PM2-managed; the workflow header still described itself as disabled pending a cutover that has happened. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- STAGING-DEPLOYMENT.md quoted `docker compose pull --pull always`, which is not a real invocation (`--pull` belongs to `up`, and `pull` always hits the registry). The workflow runs a bare `pull`; its own inline comment is what misled me. Describes the actual behaviour instead. - .github/DEPLOYMENT.md said "everything below" is PM2-only, which swept in the Server access block — those secrets are live. Scoped the sentence. - Softened the nginx line: CORS headers come from the backend's CORSMiddleware, not nginx. Inherited from the old doc rather than introduced here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Claude finished @frankbria's task in 6m 44s —— View job GLM precision review — PR #497 (done)Concrete-defects review of the deployment-docs rewrite. Verified every technical claim against the workflow, compose, and source; posted findings inline + a summary comment on the PR. 1 defect, 2 occurrences (both have suggestion blocks inline):
Everything else checked out (compose loopback bindings, the four
Summary: #497 (comment) |
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| - | - | MongoDB Credentials | 2a87919 | docs/DATABASE_CONNECTION_STANDARD.md | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secret safely. Learn here the best practices.
- Revoke and rotate this secret.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
| cd /opt/auto-author | ||
| docker compose -f docker-compose.yml -f docker-compose.staging.yml up -d |
There was a problem hiding this comment.
[major] The recreate command omits IMAGE_TAG, which the staging overlay asserts as required — up -d errors out instead of recreating the containers.
Failure scenario: an operator edits a value in /opt/auto-author/.env (the motivating case for this PR is a Mongo password rotation) and runs this command to apply it. The staging overlay (docker-compose.staging.yml:11,13) sets image: …:${IMAGE_TAG:?IMAGE_TAG is required (e.g. sha-abc1234)}, so compose aborts during interpolation — before any container is reconciled — with IMAGE_TAG is required. The new env is never applied and the running containers keep their old (now-dead, post-rotation) password. IMAGE_TAG is a per-deploy release id that the workflow exports inline (deploy-staging-containers.yml:114) and never writes to .env, so it is not present in a manual shell. The rotation runbook in docs/DATABASE_CONNECTION_STANDARD.md step 4 has the same bug.
| cd /opt/auto-author | |
| docker compose -f docker-compose.yml -f docker-compose.staging.yml up -d | |
| cd /opt/auto-author | |
| # The staging overlay pins image: …:${IMAGE_TAG:?}, so reuse the running tag — | |
| # without IMAGE_TAG, `up -d` errors out instead of recreating the containers. | |
| export IMAGE_TAG="$(docker ps --format '{{.Image}}' | grep auto-author-backend | head -1 | sed 's/.*://')" | |
| docker compose -f docker-compose.yml -f docker-compose.staging.yml up -d |
| 4. `cd /opt/auto-author && docker compose -f docker-compose.yml -f docker-compose.staging.yml up -d` | ||
| — **recreate, not restart**; a restarted container keeps its old environment. |
There was a problem hiding this comment.
[major] Step 4 omits IMAGE_TAG, which docker-compose.staging.yml asserts as required — the recreate never runs. Same root cause as the recreate block in docs/STAGING-DEPLOYMENT.md.
Failure scenario: this is the runbook for the exact incident that prompted this PR. After rotating the Atlas password (step 1) and editing MONGODB_URI (step 3), the operator runs step 4. Because the overlay asserts ${IMAGE_TAG:?…}, compose fails with IMAGE_TAG is required (e.g. sha-abc1234) and the containers are not recreated — so the new password is never loaded and the backend starts failing on reconnect. The command should set IMAGE_TAG to the currently-deployed tag (a pure env change must not also move the release).
| 4. `cd /opt/auto-author && docker compose -f docker-compose.yml -f docker-compose.staging.yml up -d` | |
| — **recreate, not restart**; a restarted container keeps its old environment. | |
| 4. Set `IMAGE_TAG` to the running tag first — the overlay's `${IMAGE_TAG:?}` makes `up -d` error out instead of recreating: | |
| `cd /opt/auto-author && export IMAGE_TAG="$(docker ps --format '{{.Image}}' | grep auto-author-backend | head -1 | sed 's/.*://')" && docker compose -f docker-compose.yml -f docker-compose.staging.yml up -d` | |
| — **recreate, not restart**; a restarted container keeps its old environment. |
GLM precision review — PR #497Scope: concrete defects only (style/architecture covered separately). Every factual claim in the rewrite was checked against the workflow, compose, and source — all accurate except the two recreate commands below.
Both have suggestion blocks on the inline comments (reuse the running tag via Note: the GitGuardian flag at |
Fallout from a real incident today: rotating the Mongo password, the docs said to update the
MONGODB_URIGitHub secret. That does nothing — staging moved to containers on 2026-08-12 (#484), and the live workflow reads application config from/opt/auto-author/.envon the box, which no workflow writes.Four documents still described the retired PM2 path as current.
Changes
Deleted —
docs/GITHUB_SECRETS_SETUP.mdFramed
MONGODB_URI/DATABASE_NAMEas E2E-test secrets.e2e-staging-tests.ymlreferences neither.Rewritten —
docs/STAGING-DEPLOYMENT.md(791 → 196 lines)The bulk described a machine this project doesn't use: host
frankbria-inspiron-7586, PostgreSQL 14,psql/VACUUM ANALYZE,/home/frankbria/staging/...paths — for a MongoDB app on a shared VPS. Kept and updated the two parts that were still true:127.0.0.1:8000:8000,127.0.0.1:3002:3002) rather than PM2's--hostflags. The ufw baseline and the 2026-07-10 off-box verification are preserved verbatim.Added what was missing: that the box
.envis the source of truth, that editing it needsup -d(recreate) notrestart, and container-flavoured troubleshooting.Kept and corrected —
docs/DATABASE_CONNECTION_STANDARD.mdThe standard itself is still true and still enforced in code (
base.py:33,auth.ts:156), so deleting it would have thrown away the one doc that was right. Replaced the dead secret →DATABASE_URLplumbing with the.env/compose reality, and added the missing reason: a db name in the path becomesdefaultauthdb, whichauthSourcedefaults to, so it breaks Atlas auth — and is ignored by both services anyway. Also adds password percent-encoding rules and a rotation runbook.Corrected —
.github/DEPLOYMENT.mdAdded a which-workflow-reads-what table and the Tailscale secrets the live deploy uses (
TS_CLIENT_ID,TS_AUTH_SECRET,STAGING_TS_HOST); marked the PM2 env-file layout as the retired path.Corrected —
CLAUDE.md,deploy-staging-containers.ymlheaderBoth still called staging PM2-managed. The workflow header still described itself as disabled pending a cutover that has already happened.
Verification
:?assertions are right, theauthSourceclaim is correct, and — the main risk with 838 removed lines — that nothing still-true was dropped.d0a5079: I had quoteddocker compose pull --pull always, which is not a valid invocation (the workflow's own inline comment misled me);.github/DEPLOYMENT.mdsaid "everything below" is PM2-only, sweeping in the live Server access secrets; the nginx line credited it with CORS headers that come from the backend'sCORSMiddleware.deploy-staging-containers.ymlre-parsed after the comment edit — 8 steps,image_taginput intact.Not done
The
MONGODB_URI/DATABASE_NAMEGitHub secrets and the two.disabledPM2 workflows are left in place. The cutover is one day old and those workflows are the rollback path; deleting the secrets now would disarm it silently.STAGING-DEPLOYMENT.mdsays to remove them once containers have run without a rollback long enough to trust (#427 AC 8).The only remaining mention of the deleted file is in
docs/CHANGELOG.md:154, inside a historical entry recording what a past PR did. Left as-is — that's a record, not an instruction.🤖 Generated with Claude Code