← back to Secrets Manager
secrets viewer: add read-only /rotation page (renders ROTATION-CHECKLIST.md as status cards)
4e224bae6fcdf0d6094e98ba5ca796549dc57b88 · 2026-06-03 08:30:33 -0700 · SteveStudio2
- new /rotation route + markdown→HTML renderer (cards w/ outstanding/done pills, summary counts)
- nav link from main viewer page
- checklist: added items 4 (SHOPIFY_ADMIN_TOKEN burned) + 5 (repl_user pw lost on sub drop)
- page shows key names + mint URLs + route-back commands only — never secret values
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Files touched
M ROTATION-CHECKLIST.mdM viewer.js
Diff
commit 4e224bae6fcdf0d6094e98ba5ca796549dc57b88
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date: Wed Jun 3 08:30:33 2026 -0700
secrets viewer: add read-only /rotation page (renders ROTATION-CHECKLIST.md as status cards)
- new /rotation route + markdown→HTML renderer (cards w/ outstanding/done pills, summary counts)
- nav link from main viewer page
- checklist: added items 4 (SHOPIFY_ADMIN_TOKEN burned) + 5 (repl_user pw lost on sub drop)
- page shows key names + mint URLs + route-back commands only — never secret values
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
ROTATION-CHECKLIST.md | 27 ++++++++++++
viewer.js | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 141 insertions(+)
diff --git a/ROTATION-CHECKLIST.md b/ROTATION-CHECKLIST.md
index f17152c..62febca 100644
--- a/ROTATION-CHECKLIST.md
+++ b/ROTATION-CHECKLIST.md
@@ -57,3 +57,30 @@ Pre-flight (read-only, 2026-06-01) confirmed safe to run:
~/Projects/_shared/scripts/rotate-pg-scoped.sh ~/Projects/Norma sdcc norma_app_user NORMA_APP_DB_PASSWORD
```
**Caveats:** (a) the script is **LOCAL-only** (`127.0.0.1:5432`) — it does not touch prod Kamatera; (b) it's **interactive** (type the new ≥16-char pw twice at the prompt — the header's "pipe via stdin" is stale); (c) it does **not** rotate `dw_admin` — that's item #1 above.
+
+---
+
+## Newly identified (2026-06-03)
+
+## 4. `SHOPIFY_ADMIN_TOKEN` ⬜ OUTSTANDING (P1 — blocks DW catalog→Shopify push)
+
+- **Exposed / status:** likely the burned post-bubbe token. The full-monte Phase 8 catalog push reads `process.env.SHOPIFY_ADMIN_TOKEN` and currently gets `undefined` → every push auth-fails silently (catch-up "succeeded" counts are error-caught lies, 0 real writes). DW catalog has not pushed to Shopify since ~Apr 30.
+- **Mint:** Shopify admin → Apps → (custom app) → API credentials → revoke old Admin API access token, install/reveal a new one.
+- **Secret key name:** `SHOPIFY_ADMIN_TOKEN` (confirm against `routes.json`).
+- **Route back:**
+ ```
+ printf 'SHOPIFY_ADMIN_TOKEN=<NEW_TOKEN>' | node ~/Projects/secrets-manager/cli.js import-paste
+ ```
+ Then ensure the full-monte env actually sources it (sourced `.env` or a crontab global `SHOPIFY_ADMIN_TOKEN=` line) — Phase 8 has no `.env` and cron doesn't export it.
+- **Verify:** `node ~/Projects/secrets-manager/cli.js check` + a single Phase-8 dry push shows a real 200/201 write.
+
+## 5. PG `repl_user` replication password ⬜ OUTSTANDING (unblocks the frozen dw_unified mirror)
+
+- **Exposed / status:** the password lived only inside the Mac2 subscription's `subconninfo`, which was removed when the broken subscription was dropped 2026-06-03 — so it's now unavailable locally. Not a leak; a loss. The dw_unified mirror (Vendors/edges/settlement panels) stays frozen until this is reset and the subscription recreated.
+- **Console steps (Kamatera publisher):** `ALTER ROLE repl_user WITH PASSWORD '<NEW_PW>';` (also clear the stray `spoon_all_designs_legacy_20260601` table from publication `dw_unified_pub` — see `~/cncp-starter/yolo-queue/pending-approval/mirror-resync-FIX.md`).
+- **Secret key name:** propose `REPL_USER_DB_PASSWORD` (new route — does not exist in routes.json yet).
+- **Route back:**
+ ```
+ printf 'REPL_USER_DB_PASSWORD=<NEW_PW>' | node ~/Projects/secrets-manager/cli.js import-paste
+ ```
+- **Verify:** rerun `REPL_PW=<NEW_PW> bash ~/cncp-starter/yolo-queue/run-mirror-resync.sh`; `max(synced_at)` jumps to ~now + the CNCP mirror-alert banner clears.
diff --git a/viewer.js b/viewer.js
index 1b831ca..f718f1f 100644
--- a/viewer.js
+++ b/viewer.js
@@ -35,6 +35,7 @@ const ROOT = __dirname;
const REGISTRY = path.join(ROOT, 'registry.json');
const MASTER_ENV = path.join(ROOT, '.env');
const REVEAL_LOG = path.join(ROOT, 'viewer-reveal.log');
+const ROTATION_DOC = path.join(ROOT, 'ROTATION-CHECKLIST.md');
function isLoopback(req) {
const addr = req.socket && req.socket.remoteAddress;
@@ -144,6 +145,7 @@ function renderPage() {
</head><body>
<h1>Secrets Viewer</h1>
<p class="sub">Local-only · binds to <code>127.0.0.1:${PORT}</code> · reads <code>${htmlEsc(path.basename(REGISTRY))}</code> · revealed values are logged to <code>${htmlEsc(path.basename(REVEAL_LOG))}</code></p>
+ <p class="sub">🔄 <a href="/rotation" style="color:#7f1d1d;font-weight:600">Items we need to rotate →</a></p>
<div class="toolbar">
<input type="search" id="q" placeholder="Filter by key or label (e.g. eleven, godaddy, shopify)" autocomplete="off">
@@ -246,6 +248,114 @@ function renderPage() {
</body></html>`;
}
+// ── Rotation view ────────────────────────────────────────────────────────────
+// Renders ROTATION-CHECKLIST.md (the authoritative "items we need to rotate"
+// list) as status cards. Read-only; the doc holds NO secret values (key names +
+// mint URLs + route-back commands only), so this page is safe to display.
+function mdInlineEsc(s) {
+ // input is raw markdown; escape HTML first, then apply a few inline rules.
+ let h = htmlEsc(s);
+ // protect inline code spans
+ const codes = [];
+ h = h.replace(/`([^`]+)`/g, (_, c) => { codes.push(c); return '