Repository navigation
TC-1482: wire optional NODE_STATS_READ_TOKEN into the production deploy (companion to #370) - #371
Conversation
Companion to #370. Optional sealed env value, compose environment line, N0 template hash and operator docs. Unset keeps GET /admin/stats disabled.
Adds the /admin/stats route label to the log-shipper field list (copy of the tinycloud-dev canonical list), the ingress route map and the Vector boundary cases. Re-pins log-shipper/canonical.json to the tinycloud-dev PR head, so the pin MUST be updated after that PR merges. Regenerates the embedded Vector config in the N0 compose and its fixture, and moves the N0 template lock. Route template plus status only; no query, credential, body or address (TC-961).
# Conflicts: # .github/workflows/docker.yml # docs/releasing.md # docs/runbooks/tc-959-n0-log-shipping.md
|
APPROVE: see TC-1482 (reviewed exact head fe16c31) Independent security review (Opus gate) of exact head Hashes, recomputed with docker.yml's own
Secrets: environment secret → step env → Release-note answers (Naomi):
Low: docs should carry the (c) message, the rollback impact, the removal steps, the double restart and hex tokens. No workflow refusal of stats token == admin secret. The +1 test stubs CI at fe16c31 when posting: pass: Build dstack ingress image, Version guard, at-rest harness, boundary, build (workspace), capabilities, clippy (workspace), fmt (workspace), hosted-compose-proof, m1-realdata, plan, separate workspace lockfiles, w5 workspace lockfile. Pending: |
…ment the release notes (TC-1482) - docker.yml: when PROD_TINYCLOUD_NODE_STATS_READ_TOKEN is set, refuse a value equal to the admin secret or shorter than 32 bytes before the sealed file is written, with constant messages that name no value. - test-deploy-recovery.py: cover both refusals, and the stub mode where the CVM's allowed_envs already names NODE_STATS_READ_TOKEN and the secret is unset (fails before any CVM mutation, also for the rollback path). - docs/releasing.md: release-note items for the compose-hash change, the node DID, the never-delete rule, the double restart of the first deploy, and the token generation.
|
APPROVE: see TC-1482 (reviewed exact head 03810e2) |
logging: log /admin/stats as its own route, status only (TC-1482)
# Conflicts: # CHANGELOG.md
… revision 9bda95fa (sha256 unchanged)
|
APPROVE: see TC-1482 (main-merge only; +/- lines byte-identical vs ed81bd1 (= the merged #372 tree, 9321dbf); head 68ca445) Detail: merged origin/main a742ab8 (1.21.2) into 9321dbf with a merge commit (d395a84). The only conflict was CHANGELOG.md: this branch's Unreleased entry and main's [1.21.2] section sat at the same spot; resolved by keeping both (Unreleased first, then [1.21.2] untouched). The PR diff against main has the same 13 files as before; the patch-id differs (78df835e… vs 114b21eb…) only because main's 1.21.2 section moved the CHANGELOG context; the added/removed lines are byte-identical per file for all 13 files (sha256 of the +/- lines compared per file: docker.yml, CHANGELOG.md, redacted-logging.conf, test-redacted-logging.sh, the compose, docs/releasing.md, the tc-959 runbook, canonical.json, cases.mjs, diagnostics.json, fields.json, the fixture, test-deploy-recovery.py). The compose and its hashes are unchanged (raw 32a002ef…, template 79469f97…). |
TC-1482 deploy wiring, companion to #370 (
GET /admin/stats, bearerNODE_STATS_READ_TOKEN).Base:
main. Ships with #370 in the release after 1.21.2; review together. Not for 1.21.2. Do not merge before #370. No deploy, Phala call or Docker was run for this PR.Compose hash changes
docker-compose.dstack-postgres.yamlgains one line, so the reviewed N0 template lock changes:1228d81927fc0a3fbba85745103e77b3112606f5d314d15974d400b2224093507fabba70e71423faa2c8b61981d4a7c95ac7c2552074af81c0877af774d6b3838f67b3b25136537c65b154b8729b0a1a7d9911b9963acc121a303cb9d806a6e7ae497fed720da12219999f4bb8573fb81b235c25086c96142e87f11e948b5832docker.ymln0_template_hashandscripts/ci/fixtures/tc959-n0-compose.yaml(byte-identical to the compose) move with it.ops/rollback/*hashes are unchanged. Release notes for that release must say the compose hash changed.Files and where the line was added
docker-compose.dstack-postgres.yaml:tinycloud.environment, directly afterTINYCLOUD_ADMIN_SECRET:NODE_STATS_READ_TOKEN: "${NODE_STATS_READ_TOKEN:-}". The:-form (already used in this file) makes it optional and warning-free when unset. This is the only compose edit; it is the only compose file that passes the admin secret.scripts/ci/fixtures/tc959-n0-compose.yaml: same line (test fixture copy of the compose)..github/workflows/docker.yml, jobdeploy-phala:n0_template_hashand its comment (validate step).Deploy to Phala Cloudenv:PHALA_ENV_NODE_STATS_READ_TOKEN: ${{ secrets.PROD_TINYCLOUD_NODE_STATS_READ_TOKEN }}, afterPHALA_ENV_TINYCLOUD_ADMIN_SECRET.required_vars. A separate single-line check (CR/LF fails before any CVM mutation) after that loop..phala-prod.env:NODE_STATS_READ_TOKEN=is written only when the value is non-empty.docs/releasing.md: new sectionNODE_STATS_READ_TOKEN (TC-1482): compose hash change(after the quota/billing paragraph, ~l.150); template/raw hash in the N0 requirements list and the 12c recovery paragraph.docs/runbooks/tc-959-n0-log-shipping.md: hash table row..github/workflows/docker.yml(review round 1, L2): when the token is set, the step refuses, before writing.phala-prod.env, a token equal toPHALA_ENV_TINYCLOUD_ADMIN_SECRET(::error::NODE_STATS_READ_TOKEN must differ from TINYCLOUD_ADMIN_SECRET) and a token shorter than 32 bytes (::error::NODE_STATS_READ_TOKEN must be at least 32 bytes; surrounding whitespace not counted;wc -cbytes). Constant messages, no value printed. Consistent with feat(admin): read-only GET /admin/stats owner list (TC-1482) #370, where such a token makes the node keep the route at 404.scripts/ci/test-deploy-recovery.py: unset/empty token does not block the deploy and is absent from the sealed file; set token is sealed once and never appears in logs; a multi-line token fails beforephala deploy. New (L2): equal-to-admin, 31-byte, whitespace-padded 31-byte, whitespace-only and 30-byte multibyte tokens are refused before any CVM mutation and before the sealed file is written; 32-byte, 64-hex and 32-byte multibyte tokens pass (mutation check: removing both guards fails all five refusal cases). New (L3): stub mode where the CVM'sallowed_envsalready namesNODE_STATS_READ_TOKENand the secret is unset or empty:success False, nocvm-deploy, message::error::allowed_envs synchronization failed during complete whitelist validation; response details withheld.; the same for the pre-N0 rollback path, which passes with the secret present. The stub stands in forsync.mjs --check(the test also asserts the real message and phase string exist indocker.yml).Secret handling
Same path as
TINYCLOUD_ADMIN_SECRET: GitHubproductionenvironment secret, then the stepenv:, then the 0600.phala-prod.env(removed afterwards), thenphala deploy -e <file>. The value is never in a repo file, argv or logs (argv carries only the file name). That existing path already keeps secrets off argv; nothing was copied from a pattern that does not.Unset token
Optional: the line is not written,
docker compose config --quietstill passes (:-),--validate-configdoes not read it, and the node starts with/admin/statsdisabled (404, per #370). Once a deploy has put the name in the CVMallowed_envs, later deploys must keep supplying it (existing whitelist check).Rollback files
ops/rollback/pre-n0-compose.yamlandpre-n0-stop-local-logs.yamlare unchanged: they are pinned by raw hash, restore the 1.20.6 image which does not read the variable, and rollback therefore leaves the route absent.Operator steps (do not do before review)
Bobbie generates a 32-byte hex token (
openssl rand -hex 32, 64 characters); Amos stores it as thePROD_TINYCLOUD_NODE_STATS_READ_TOKENenvironment secret (stdin, never printed) so the release deploy seals it into the Phala env; the same value is set as OpenKey'sNODE_STATS_READ_TOKEN. It must differ fromPROD_TINYCLOUD_ADMIN_SECRETand be at least 32 bytes; the deploy refuses otherwise.docs/releasing.mdcarries the release-note items (registration/KMS, node DID, never-delete rule, double restart of the first deploy, token generation).Checks run
python3 scripts/ci/test-deploy-recovery.py(25 tests, offline stubs) OK;actionlintondocker.ymlreports the same two shellcheck findings asmain; YAML parse of all compose files;node --testfor the logship suites (33) OK.docker compose configwas not run (no Docker).Overlap
The #370 bullet in
docs/releasing.md(~l.112-119, "not passed to the CVM bydocker.yml...") lives only on #370's branch, so #370 owns it; it is stale once both land, and whoever merges second updates it. #370 editsdocs/releasing.mdat ~l.109-119 and README/CHANGELOG; this PR does not touch those hunks (a trial merge with #370 had no conflicts; the #370 bullet saying the token is not wired will be stale once both land). Older open PRs #342, #288, #325, #272, #231 also touch compose/docker.ymlbut predate main's current compose.