Repository navigation
wiki: GET /api/version + npm run deploy refuses + narrower agent wrangler rules - #54
Conversation
The live Worker could not be tied to a commit without Wrangler access, and 'npm run deploy' (plain wrangler deploy of ./public) would silently replace the production Brain release selector and asset tree. - wrangler.jsonc binds version_metadata (CF_VERSION_METADATA). - GET /api/version returns the Worker Version id/tag/upload time, the git SHA stamped by npm run deploy (WIKILEAN_GIT_SHA, '<sha>[-dirty]'), and the selected Brain release with its authority git commit. Promoter deploys carry no stamp; their Worker source is the release's authority commit. - npm run deploy now runs scripts/deploy.ts: it refuses unless the local public/assets/brain/current.json names the same release and manifest as the live selector, then runs wrangler deploy --var WIKILEAN_GIT_SHA:<sha>. --dry-run skips the selector check. The Brain promoter calls wrangler directly and never passes through this script.
…arg allowlist - The upload replaces the live selector, so the guard now requires every field to match (audited_at and previous_* rollback pointers included), and the refusal names the build-public flags that reproduce the live selector. - The local release directory must hold the manifest the selector names (sha256 of releases/<manifest_sha256>/release.json). - Real deploys accept only --message/--tag; --assets, --config, --env, positionals etc. are refused. --var goes last (wrangler's --var is a greedy array). Ambiguous --dry-run forms and npm-consumed --dry-run are refused. - The -dirty stamp only considers wiki/src and the Worker config files; fetch and spawn failures are printed; main-module detection resolves symlinks. - /api/version reports the exact manifest_sha256 alongside release_id.
|
Superseded by the review of Posted by the WikiLean PR swarm (lead); updated 2026-10-17. |
Status review (2026-10-14): ❓ Needs an owner decisionThe Decision: is a guarded manual deploy a sanctioned path?
(The 2026-10-04 attempt was reconciled on 2026-10-08, so nothing is blocked today.) Nits
Conflicts: #47 conflicts in To ship: this is release-affecting ( 🤖 Automated status pass by Claude Code over all 18 open PRs (#46–#63), posted for the repo owner. An independent verifier re-checked each finding. All 18 heads were also merged and tested together in a scratch tree; the only test failure that comes from combining them is #47 × #55 (three other pairs had mechanical text conflicts). Reviewed head: |
Resolves the wiki/src/index.ts import conflict with #47 by keeping both imports; registerVersionRoutes stays after registerSecurityHeaders (and registerRepoRoutes), so the security headers wrap /api/version. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…row agent wrangler rules Production deploys go only through the Brain release promoter (#53), so a guarded manual `npm run deploy` contradicted that policy, and its guard could be bypassed and checked only two files of the tree it uploads. - `npm run deploy` now prints where deploys go and exits 1. scripts/deploy.ts and its test are gone. - GET /api/version drops git_sha/git_dirty and WIKILEAN_GIT_SHA. Only the deleted script set the stamp, so it would always be null. The route keeps the Worker Version metadata and the Brain release id, manifest digest and authority commit. Comments call the promoter's brain-<hex12>-<attempt> tag evidence of a promoter deploy, not proof. - AGENTS.md, CLAUDE.md, wiki/README.md, the release runbook and the activation record now say `npm run deploy` refuses and never to run `wrangler deploy` directly. They name `wrangler rollback` as the only emergency lever, and say a forward hotfix path would be a journaled promoter mode. - .claude/settings.json: drop the pre-approved env-prefixed bare `npx wrangler deploy`. Replace `npx wrangler *` with read-only deployments/versions/tail/whoami rules and local-only `d1 execute --local`, with an ask rule on any `--remote`. Deny deploy, versions deploy/upload, rollback and secret put/delete/bulk for agent sessions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…te migrations, --install-skills The deny list covered deploy, version uploads, rollback and secrets. It now also denies `wrangler delete` (deletes the Worker), `triggers deploy` (routes and cron triggers), `d1 migrations apply --remote` (AGENTS.md says never to use it: remote tracking is out of sync) and the global `--install-skills` flag, which writes agent configuration from any otherwise read-only command. Bare forms without arguments are listed too. All of these already prompted instead of running; now they are refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolve wiki/src/index.ts by keeping both route registrations: registerCompanionRoutes (from #64 on main) and registerVersionRoutes (this PR). The routes don't overlap, and both come after registerSecurityHeaders.
|
Conflict resolved; ready to merge after two small fixes (reviewed at
One body fix: since #68, Posted by the WikiLean PR swarm (lead). |
Fields, when each is null, the always-200 no-store response, and that a brain- version tag is evidence of a promoter deploy, not proof. The row sits after /api/auth/* so it doesn't collide with #50's /api/runs row at the end of the table.
…ote-first migrations wrangler d1 delete and d1 time-travel restore act only on the remote database and take no --remote flag, so the --remote ask rule never saw them, and without a TTY wrangler's confirmation falls back to yes. Deny both, with --no-install twins. The migrations deny now matches 'apply --remote <db>' as well as 'apply <db> --remote', and the --remote ask rule gets its --no-install twin.
wiki: GET /api/version + npm run deploy refuses + narrower agent wrangler rules
Problem
GET /api/version,/api/health,/versionand/healthzall returned 404. Onlywrangler deployments status, which needs Cloudflare credentials, shows which Worker version is live.npm run deployis a barewrangler deploy. It uploads the Worker built from localwiki/srctogether with the whole localwiki/public, which replaces the Brain selector and the entire asset tree. It runs outside the promoter, so there is no journal and no canary. Since Docs: record the Brain activation and correct project status #53, the docs say production deploys go only throughsite/ops/brain-promote-release.sh, but only the docs enforce that..claude/settings.jsonallowednpx wrangler *, which coversdeploy,versions deploy/upload,rollbackandsecret put. It also pre-approved an env-prefixed barenpx wrangler deploy.Change
GET /api/version(public,Cache-Control: no-store, no D1, registered afterregisterSecurityHeadersso the security headers wrap it):{"ok":true, "worker":{"version_id":"…","version_tag":"…","uploaded_at":"…"}, "brain_release":{"release_id":"sha256:…","manifest_sha256":"…","git_commit":"<authority commit>"}}workercomes from Cloudflare'sversion_metadatabinding,CF_VERSION_METADATAinwiki/wrangler.jsonc. The promoter copies that file verbatim, so the binding needs no dashboard setup.brain_releaseis the release the asset selector names, plusauthority.git_commitfrom itsrelease.json. It isnullwhen no release resolves, and the route never 503s.brain-<release hex12>-<attempt>(site/ops/brain_promote_release.py). That tag is evidence of a promoter deploy, not proof: it is a free-form--tagthat anyone with deploy credentials could set. For a promoter deploy, the Worker source isgit_commit's, because the promoter only deploys a checkout whose release-affecting paths match the release's authority commit./api, soRESERVEDalready covers it.npm run deployrefuses. It printsnpm run deploy is disabled: production deploys go only through site/ops/brain-promote-release.sh (docs/BRAIN-RELEASE-RUNBOOK.md)to stderr and exits 1. The promoter never callsnpm run deploy, so the promotion path is unaffected.Docs (AGENTS.md, CLAUDE.md, wiki/README.md, docs/BRAIN-RELEASE-RUNBOOK.md, docs/BRAIN-ACTIVATION-2026-10-04.md). Where #53 said "never plain
npm run deploy/wrangler deploy", the docs now say:npm run deployrefuses.wrangler deploydirectly.wrangler rollbackto a recorded version, per the runbook's "Wrangler rollback" section.AGENTS.md and CLAUDE.md stay identical past line 1.
wiki/README.md's Routes table also gets aGET /api/versionrow: the fields, when each is null, and the evidence-not-proof caveat onbrain-tags..claude/settings.json(agent permission rules):npx wrangler deploy.Bash(npx wrangler *)with read-only and local rules:deployments list|statusandversions list|view, each with and without--no-install, since the runbook uses the--no-installform.tailandwhoami.d1 execute wikilean --local, for the backup restore drill.askrules:Bash(npx wrangler * --remote*)and its--no-installtwin, so the--localprefix rule can never pre-approve a command that reaches the remote database.denyrules fordeploy,versions deploy,versions upload,rollback,secret put|delete|bulk,delete(the Worker),triggers deploy,d1 deleteandd1 time-travel restore(both act only on the remote database, take no--remoteflag, and confirm themselves when there's no TTY),d1 migrations applywith--remotebefore or after the database name, and the global--install-skillsflag. Each is listed with and without--no-install(the deploy-class verbs also in bare form,d5d2a55a). Rollback stays a human action, as the runbook already requires.wrangler devis not pre-approved:--remote/-rruns it "with access to production resources", and a prefix rule can't exclude that.npm run devwas never allowlisted.d1 executeandkv key putnow prompt instead of running unasked.Dropped from the original PR, and why
wiki/scripts/deploy.ts,wiki/test/deploy-guard.test.ts). It contradicted Docs: record the Brain activation and correct project status #53's promoter-only rule, and a passing guard still ran a real deploy from any HEAD with no journal or canary. Review also found argument forms that skipped the checks and still deployed. The guard checked only the selector andrelease.json, not the artifacts or index trees it uploads. "Don't deploy during an open promotion attempt" was a comment, not a check. Deleting the script closes all of these.git_sha/git_dirtyandWIKILEAN_GIT_SHA. Only the deleted script set the stamp, and the promoter passes no--var, so these fields would always be null. For a promoter deploy,brain_release.git_commitidentifies the source.There is no break-glass deploy path. If the promoter itself is broken in an incident, the runbook's
wrangler rollbackis the lever. A forward hotfix would need a new journaled promoter mode, which would be a separate decision.How tested
npx tsc --noEmit -p .passes.npx vitest run: 40 files and 932 tests pass.test/version.test.tscovers metadata plus a resolved release, the null fallbacks with no binding and no release, andno-storeon both./api/versionreturned HSTS,X-Frame-Options: DENY,frame-ancestors 'none'andCache-Control: no-store.npm run deploy,npm run deploy --dry-run,npm_config_dry_run=true npm run deployandnpm run deploy -- --dry-runall print the refusal and exit 1. With extra--arguments, npm appends them afterexit 1, so the shell also prints a harmlessexit: too many arguments.site/ops/test_brain_release_authority.py(7 tests),test_brain_nightly.py(23) andtest_brain_promote_release.py(59) pass..claude/settings.jsonparses as JSON. Replaying 20 representative wrangler commands through Claude Code's wildcard matcher (its escaping,*handling and deny > ask > allow order) gives the intended result for each:d1 delete,d1 time-travel restoreandd1 migrations apply --remotein either flag order are refused, remoted1 executeprompts, and the--local,whoamianddeployments listforms stay allowed.4593c994. The only conflict was the route registration inwiki/src/index.ts, where bothregisterCompanionRoutesandregisterVersionRoutesare kept; this PR's own changes are unchanged by the merge, and CI passed on it.Release impact
wiki/src,wiki/wrangler.jsoncandwiki/package.json. This ships only through release B and an approved promotion; nothing deploys on merge. There is no D1 migration, no secret, and no dashboard step..claude/settings.json,AGENTS.md(since Release policy: AGENTS.md and CONTRIBUTING.md are release-neutral #68),CLAUDE.md,wiki/README.md,docs/andwiki/test/. The settings change takes effect for agent sessions as soon as this merges.main.wiki/wrangler.jsoncchange while a promotion attempt sits between--executeandfinal_state. None is open: the 2026-10-04 attempt was reconciled on 2026-10-08.What Jack must do
Nothing to configure. After release B is promoted, run
curl https://wikilean.jackmccarthy.org/api/version. It should show aworker.version_tagofbrain-<B hex12>-<attempt>and abrain_release.git_commitequal to B's authority commit.🤖 Generated with Claude Code