Skip to content

docs(deploy): make the deployment docs describe the container deploy - #497

Open
frankbria wants to merge 2 commits into
mainfrom
docs/deploy-docs-match-container-deploy
Open

docs(deploy): make the deployment docs describe the container deploy#497
frankbria wants to merge 2 commits into
mainfrom
docs/deploy-docs-match-container-deploy

Conversation

@frankbria

Copy link
Copy Markdown
Owner

Fallout from a real incident today: rotating the Mongo password, the docs said to update the MONGODB_URI GitHub secret. That does nothing — staging moved to containers on 2026-08-12 (#484), and the live workflow reads application config from /opt/auto-author/.env on the box, which no workflow writes.

Four documents still described the retired PM2 path as current.

Changes

Deleted — docs/GITHUB_SECRETS_SETUP.md
Framed MONGODB_URI / DATABASE_NAME as E2E-test secrets. e2e-staging-tests.yml references 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:

Added what was missing: that the box .env is the source of truth, that editing it needs up -d (recreate) not restart, and container-flavoured troubleshooting.

Kept and corrected — docs/DATABASE_CONNECTION_STANDARD.md
The 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_URL plumbing with the .env/compose reality, and added the missing reason: a db name in the path becomes defaultauthdb, which authSource defaults 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.md
Added 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.yml header
Both still called staging PM2-managed. The workflow header still described itself as disabled pending a cutover that has already happened.

Verification

  • Every claim fact-checked against the workflow, compose, and source files by an independent reviewer (opencode/GLM) before this PR. It confirmed the secrets list is exact, the compose bindings and :? assertions are right, the authSource claim is correct, and — the main risk with 838 removed lines — that nothing still-true was dropped.
  • Three findings from that pass, all fixed in d0a5079: I had quoted docker compose pull --pull always, which is not a valid invocation (the workflow's own inline comment misled me); .github/DEPLOYMENT.md said "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's CORSMiddleware.
  • deploy-staging-containers.yml re-parsed after the comment edit — 8 steps, image_tag input intact.

Not done

The MONGODB_URI / DATABASE_NAME GitHub secrets and the two .disabled PM2 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.md says 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

frankbria and others added 2 commits August 13, 2026 10:26
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>
@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

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

severity file:line finding
major docs/STAGING-DEPLOYMENT.md:72-73 Recreate command omits IMAGE_TAG; the overlay's ${IMAGE_TAG:?} makes up -d error out, so an edited .env value (e.g. rotated Mongo password) is never applied.
major docs/DATABASE_CONNECTION_STANDARD.md:112-113 Same root cause in the password-rotation runbook — the exact incident procedure this PR is about.

Everything else checked out (compose loopback bindings, the four :? assertions, DATABASE_URL remap, secrets table, 8 workflow steps + image_tag, base.py:33, auth.ts:156, config.py:53, conftest.py TEST_MONGO_URI, /health Mongo-ping→503-checks, no dangling refs to the deleted file). GitGuardian flag on line 159 is a pa$$word placeholder — false positive.

  • Gather PR context and read existing comments
  • Read each changed doc + the real workflow/compose/source
  • Verify technical claims against real code
  • Confirm/discard each candidate finding
  • Post inline comments + summary comment

Summary: #497 (comment)

@gitguardian

gitguardian Bot commented Aug 13, 2026

Copy link
Copy Markdown

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
- - MongoDB Credentials 2a87919 docs/DATABASE_CONNECTION_STANDARD.md View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. 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


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

Comment on lines +72 to +73
cd /opt/auto-author
docker compose -f docker-compose.yml -f docker-compose.staging.yml up -d

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.

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

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

Comment on lines +112 to +113
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.

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.

[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).

Suggested change
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.

@github-actions

Copy link
Copy Markdown
Contributor

GLM precision review — PR #497

Scope: 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.

severity file:line finding
major docs/STAGING-DEPLOYMENT.md:72-73 Recreate command omits IMAGE_TAG; the staging overlay's ${IMAGE_TAG:?} makes up -d error out, so an edited .env value (e.g. a rotated Mongo password) is never applied. IMAGE_TAG is a per-deploy id the workflow exports inline and never writes to .env, so it's absent in a manual shell.
major docs/DATABASE_CONNECTION_STANDARD.md:112-113 Same root cause in the password-rotation runbook step 4 — the exact procedure for the incident that motivated this PR fails as written.

Both have suggestion blocks on the inline comments (reuse the running tag via docker ps). Two occurrences of one bug; not approving or requesting changes.

Note: the GitGuardian flag at DATABASE_CONNECTION_STANDARD.md:159 is staging_user:pa$$word (percent-encoded placeholder), not a live credential — no action.

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.

1 participant