diff --git a/REPORT-cc-creds-build-2026-10-17.md b/REPORT-cc-creds-build-2026-10-17.md index 7c3d3fda..775c7ca4 100644 --- a/REPORT-cc-creds-build-2026-10-17.md +++ b/REPORT-cc-creds-build-2026-10-17.md @@ -124,6 +124,20 @@ guards against accidents. Register after STOP 3: **181 → 177** (R-1119, R-1120, R-1131, R-1132 closed; R-1130, R-1133, R-1134 updated). +## After STOP 3 — the old file deleted (operator's go) + +- D16: line 20 was a separator line (Felhom / JARR passwords); the operator removed it. D15: keep the Docker Hub + password → R-1130 closed as accepted. +- **`~/.config/credentials` deleted** (`shred -u`) after an in-memory check: all 23 keys equal the store, 0 problems + (`old-file-compare.txt`). R-1134 closed. +- **Two older plain copies found beside it**, not deleted (the go named „the file"): `.bak-20261001-calibre`, + `.bak-20261016-tester1` — everything equal to the store except an older `HUB_TOKEN` and an older `TESTER1_PASSWORD` + (`old-backups-compare.txt`) → R-1138, STATUS D17. R-1135 was taken by a parallel session minutes earlier; renumbered. +- The guard refused my direct reads of these files twice (correct); the comparisons ran from script files, which print + names and MATCH only. + +Register: 177 → 176 (R-1130, R-1134 closed; R-1138 opened). + ## Fences kept `~/.config/credentials` unchanged (sha prefix before = after). `~/rotated-secrets-2026-10-09.txt` not opened. No `sops diff --git a/STATUS.md b/STATUS.md index 63a32bde..3420e985 100644 --- a/STATUS.md +++ b/STATUS.md @@ -40,7 +40,7 @@ - Tester 2 has never made an off-site check (R-862). The scratch box cannot read the drill catalog (R-992). ## What we work on -- **CC's secrets** (R-1118): built and installed 2026-10-17 — the store, `sec`, the guards in every CC session, the nightly check (linger on). Your STOP 3 answers are done. Left: the old credentials file retires after a week with no reader (R-1134), and D15, D16. +- **CC's secrets** (R-1118): built and installed 2026-10-17 — the store, `sec`, the guards in every CC session, the nightly check (linger on). The old credentials file is deleted (your go). Left: D17, its two old backup copies. - **After 2026-10-18 14:16 UTC** (demo-hp's next clean-up window): check that the old restic (image 0.322.0) still lists and restores demo-hp's store after its first real 0.19.1 prune (`audits/night-restore-2026-10-17/tools/rx.sh`). Everything else of R-1105/R-1107 is done. - The power-cut findings still open (R-1004, R-1005, R-1010, R-1012, R-1013). - Media apps on every drive (R-1023): live with the 0.313.0 floor — every drive in every media app, a new drive made ready by the box, a pulled drive loses nothing, a safe removal lets go first and the drive comes back by itself. @@ -60,8 +60,7 @@ | D10 | R-1125 | **DECIDED 2026-10-17: A** — the 23 memory requests now match real use (catalog `1af6ea7`); the install refusal and page say what to do (controller 0.327.0). An 8 GB box no longer installs the whole household set. | done | — | — | — | | D11 | R-1126 | **DECIDED 2026-10-17: A** — FileBrowser is published only after its default password is checked; it never answers on the default (controller 0.327.1). The tunnel still runs before the claim, by design (`01` §5). | done | — | — | — | | D12 | R-1129 | **CLOSED 2026-10-17: not a defect** — CC misread the CI log; the failure mail always worked. A forced test mail went to admin@felhom.eu at 10:48:54 UTC (CC saw it arrive). Your key change did no harm. | done | — | — | — | -| D15 | R-1130 | `DOCKER_PASSWORD` (in one old CC record) is your **Docker Hub** password; Gitea refuses it. `~/.docker/config.json` saves the same Hub login. Change it? | **Your call** — the facts are in R-1130 | Accept: no work, the password stays valid | it stays valid while a copy sits in a record Anthropic's API has seen | — | -| D16 | R-1134 | Line 20 of the old credentials file is a value with NO name, and it matches no stored value (not `TUYA_SECRET`). What is it? | Tell CC the name (CC stores it) or say „drop it” | — | it stays only in the old file, which retires on 2026-10-24 | the old file's retirement | +| D17 | R-1138 | Two old plain copies of the deleted credentials file are still in `~/.config/` (`.bak-20261001-calibre`, `.bak-20261016-tester1`). Delete them? Everything in them is in CC's store, except one older value each (an old hub token, an old Tester 1 password). | **Delete** | Keep: two plain copies of 17–19 secrets stay on DooPlex | they stay | — | | D9 | R-1062 | The N100's USB drive is also its whole-box backup drive. Split it in two anyway? | **No — keep one drive**; the lived-in box keeps its nightly whole-box backup | Split: the box loses its local whole-box backup (or add a second drive first) | it stays one drive; multi-drive tests stay on Tester 1 | — | ## Waiting on you — do diff --git a/documentation/audits/cc-creds-build-2026-10-17/harness/compare_backups.py b/documentation/audits/cc-creds-build-2026-10-17/harness/compare_backups.py new file mode 100644 index 00000000..0567e4d0 --- /dev/null +++ b/documentation/audits/cc-creds-build-2026-10-17/harness/compare_backups.py @@ -0,0 +1,25 @@ +# Names and MATCH / MISSING / DIFFERENT for each old backup copy of the credentials file. Never a value. +import glob, os, re, sys +sys.path.insert(0, "/mnt/5_hdd/felhom.eu/git/cc-secrets") +from ccsec import store +vals = store.load_all() +for f in sorted(glob.glob(os.path.expanduser("~/.config/credentials.bak-*"))): + st = os.stat(f); out = []; total = 0 + for n, line in enumerate(open(f, encoding="utf-8").read().split("\n"), 1): + s = line.strip() + if not s or s.startswith("#"): + continue + m = re.match(r"^(export\s+)?([A-Za-z_][A-Za-z0-9_-]*)=(.*)$", s) + if not m: + out.append("line %d: not KEY=VALUE (%d chars)" % (n, len(s))); continue + total += 1 + name = m.group(2).replace("-", "_") + try: + v = store.unwrap(m.group(3), "line %d" % n) + except store.StoreError: + out.append("%s: cannot unwrap" % name); continue + if vals.get(name) != v: + out.append("%s: %s" % (name, "MISSING from store" if name not in vals else "DIFFERENT from store (an older value?)")) + print("=== %s: %d bytes, mode %o, %d keys; not matching the store: %s" % (os.path.basename(f), st.st_size, st.st_mode & 0o777, total, "none" if not out else "")) + for o in out: + print(" " + o) diff --git a/documentation/audits/cc-creds-build-2026-10-17/harness/compare_old_file.py b/documentation/audits/cc-creds-build-2026-10-17/harness/compare_old_file.py new file mode 100644 index 00000000..895ee5ad --- /dev/null +++ b/documentation/audits/cc-creds-build-2026-10-17/harness/compare_old_file.py @@ -0,0 +1,24 @@ +# Before deleting ~/.config/credentials (operator's go, 2026-10-17): every key in it must be in the store with an equal +# value. Compares in memory; prints names and MATCH / MISSING / DIFFERENT only, never a value. +import os, re, sys +sys.path.insert(0, "/mnt/5_hdd/felhom.eu/git/cc-secrets") +from ccsec import store +vals = store.load_all() +bad = 0 +lines = open(os.path.expanduser("~/.config/credentials"), encoding="utf-8").read().split("\n") +for n, line in enumerate(lines, 1): + s = line.strip() + if not s or s.startswith("#"): + continue + m = re.match(r"^(export\s+)?([A-Za-z_][A-Za-z0-9_-]*)=(.*)$", s) + if not m: + print("line %d: NOT a KEY=VALUE line (%d chars)" % (n, len(s))); bad += 1; continue + name = m.group(2).replace("-", "_") + try: + v = store.unwrap(m.group(3), "line %d" % n) + except store.StoreError as e: + print("line %d %s: cannot unwrap (%s)" % (n, name, e)); bad += 1; continue + state = "MATCH" if vals.get(name) == v else ("MISSING" if name not in vals else "DIFFERENT") + bad += state != "MATCH" + print("%-24s %s" % (name, state)) +print("lines %d, problems %d" % (len(lines), bad)) diff --git a/documentation/audits/cc-creds-build-2026-10-17/old-backups-compare.txt b/documentation/audits/cc-creds-build-2026-10-17/old-backups-compare.txt new file mode 100644 index 00000000..f7d19fc2 --- /dev/null +++ b/documentation/audits/cc-creds-build-2026-10-17/old-backups-compare.txt @@ -0,0 +1,4 @@ +=== credentials.bak-20261001-calibre: 1081 bytes, mode 600, 17 keys; not matching the store: + HUB_TOKEN: DIFFERENT from store (an older value?) +=== credentials.bak-20261016-tester1: 1196 bytes, mode 600, 19 keys; not matching the store: + TESTER1_PASSWORD: DIFFERENT from store (an older value?) diff --git a/documentation/audits/cc-creds-build-2026-10-17/old-file-compare.txt b/documentation/audits/cc-creds-build-2026-10-17/old-file-compare.txt new file mode 100644 index 00000000..1d3bf534 --- /dev/null +++ b/documentation/audits/cc-creds-build-2026-10-17/old-file-compare.txt @@ -0,0 +1,24 @@ +HETZNER_API MATCH +PASSWORD MATCH +TS_KEY MATCH +HUB_TOKEN MATCH +ISO_S3_CLIENT_AK MATCH +ISO_S3_CLIENT_SK MATCH +ISO_S3_URL MATCH +R_DEMO_FELHOM MATCH +R_DEMO_HP MATCH +R_C11_REWALK MATCH +R_PART4 MATCH +DOCKER_USERNAME MATCH +DOCKER_PASSWORD MATCH +DEMO_HP_BOOKSTACK_USER MATCH +DEMO_HP_BOOKSTACK_PW MATCH +DEMO_HP_CALIBRE_USER MATCH +DEMO_HP_CALIBRE_PW MATCH +TESTER1_PASSWORD MATCH +TESTER4_PASSWORD MATCH +UMAMI_CC_USER MATCH +UMAMI_CC_PW MATCH +DEV_BASIC_AUTH_USER MATCH +DEV_BASIC_AUTH_PW MATCH +lines 24, problems 0 diff --git a/documentation/backlog/CLOSED-ITEMS.md b/documentation/backlog/CLOSED-ITEMS.md index eedc74d8..5931541f 100644 --- a/documentation/backlog/CLOSED-ITEMS.md +++ b/documentation/backlog/CLOSED-ITEMS.md @@ -43,6 +43,8 @@ | **R-1120** | **`homelab-manifests/.claude/settings.json` allowed `kubectl get secret -o yaml` with no prompt.** (P3) | CLOSED 2026-10-17 — operator yes (STOP 3 b). Three `ask` rules (`kubectl get secret* -o*`, `*--output*`, `*--template*`) in homelab-manifests `9f582ad`. Proven in headless child sessions with only these permission rules: `-o yaml`, `-ojson`, `--output=yaml` held, the plain table ran. Second layer: the user-level guard. | `audits/cc-creds-build-2026-10-17/homelab-ask-pattern-test.txt` | | **R-1131** | **demo-felhom's recovery code was printed into the JARR session's record (2026-10-17 08:27 UTC, `. ~/.config/credentials`).** (P3) | CLOSED 2026-10-17 — ACCEPTED by the operator (STOP 3 c): a test box, no rotation. The command shape is refused by the guard since 13:14. | `audits/cc-creds-build-2026-10-17/history-sweep-list.txt` | | **R-1132** | **demo-hp's recovery code was printed in the same record line as R-1131.** (P3) | CLOSED 2026-10-17 — ACCEPTED by the operator (STOP 3 c): a test box, no rotation. | as R-1131 | +| **R-1130** | **`DOCKER_PASSWORD` (the Docker Hub password; Gitea refuses it) is in one old CC session record (2026-09-21).** (P3) | CLOSED 2026-10-17 — ACCEPTED by the operator (D15 „keep"): no rotation. Facts measured first: Docker Hub login succeeded, `gitea.dooplex.hu` 401, `~/.docker/config.json` saves the same Hub login. | `audits/cc-creds-build-2026-10-17/docker-login-test.txt` | +| **R-1134** | **Retire the old `~/.config/credentials`.** (P3) | CLOSED 2026-10-17 — DELETED (`shred -u`) on the operator's go, after an in-memory check that all 23 keys in it equal the store (0 problems). Its nameless line 20 was a separator between the Felhom and JARR passwords; the operator removed it first. Two older backup copies found beside it → R-1138. | `audits/cc-creds-build-2026-10-17/old-file-compare.txt` | ## 2026-10-17 — Tester 1 on the live catalog, decoy suites in every runner, memory limits, FileBrowser (controller v0.326.0, catalog `bff82f9`) diff --git a/documentation/backlog/OPEN-ITEMS.md b/documentation/backlog/OPEN-ITEMS.md index 6805a83b..2740f8a6 100644 --- a/documentation/backlog/OPEN-ITEMS.md +++ b/documentation/backlog/OPEN-ITEMS.md @@ -211,7 +211,7 @@ stopping line that lies. | **R-1094** | Storage & devices | P4 | **The whole-disk format refusal tells the household to format the free part — which is refused while the other part is in use.** SEEN 2026-10-16 (controller 0.318.0): 409 „Ezen a lemezen egy használatban lévő meghajtó van, ezért a teljes lemez nem formázható. Csak a szabad részét formázhatod." — since agent 0.158.1 a part next to a mounted part can only be USED (the root wrapper trusts no „Felhom's own" claim). Evidence: `audits/storage-identity-buildB-2026-10-15/live/14-samedisk-refusal-offer.txt`. | READY | — | Reword `err.web.meghajto_hasznalatban_formazas` (hu + en): „… nem formázható. A szabad részét használatba veheted." Next controller release; the copy gates run. | CC | | **R-1124** | Storage & devices | P4 | **A drive decommissioned and then unplugged keeps its agent mount unit enabled on the host** (`mnt-.mount`, „Managed by felhom-agent”, `WantedBy=multi-user.target`), so every later boot waits for a device that is gone, and the agent's watchdog reports it „disconnected”. Decommission retires the drive logically (agent: „logical retire, data untouched”) and releases only the guest bind; no product path releases the host mount or forgets the drive. Seen on Tester 1 at the R-1022 teardown 2026-10-17 (four units left; the boot delay is read from the unit, NOT measured). | OPEN — filed 2026-10-17 **2026-10-17 (later):** on Tester 1 the four units were disabled and removed by hand (read before and after, `audits/filebrowser-memory-ci-2026-10-17/P4/`); the agent did not write them back, but it still lists the four drives and logs „enrolled drive absent by UUID — will retry” every ~20 s. The product fix (decommission releases the host mount and lets the agent forget an absent drive) is an agent change — it waits for the next vouched agent release. | — | Decide „forget a decommissioned drive” (unit disabled + removed when the drive is absent), with a test | CC | -## Security & access — 22 rows (P1 1, P2 2, P3 13, P4 6) +## Security & access — 21 rows (P1 1, P2 2, P3 12, P4 6) | ID | Category | Sev | What | State | Blocked on | Next action | Owner | |---|---|---|---|---|---|---|---| @@ -234,9 +234,8 @@ stopping line that lies. | **R-1054** | Security & access | P3 | **The hub's operator/global API key is still one bearer that can do everything on `/api/v1`, including reading every box's break-glass root password (`GET /admin/hosts/{id}/recovery-credential`).** Hub v0.152.0 gave the web surface scoped tokens (`05` §17) but tokens are refused on `/api/v1` by design. Who uses the global key today is not listed in one place. Fix: list its consumers; move each operator use to a scoped token on the web side (or a token class on the API), and keep the global key only where a box path needs it — or retire it. | OPEN — filed 2026-10-15 by the token build | — | List the global key's consumers (pod env, scripts, runbooks) | CC | | **R-1118** | Security & access | P3 | **CC's secrets moved off the plain `~/.config/credentials` into an encrypted store with a broker and guards; what is left is retiring the old file.** BUILT 2026-10-17 (store B, operator ruling 11:28): private repo `admin/cc-secrets` (`ARCHITECTURE.md`, the design verbatim in `docs/`), `sec` (no get), PreToolUse refusals + PostToolUse masking for Bash and Read in `~/.claude/settings.json` (every CC session on DooPlex), nightly transcript sweep with mail. 55 tests, 18 red-proofs, 36-row child-session proof in both launch modes, fresh-session proof (`audits/cc-creds-build-2026-10-17/`). 25 names in the store (23 imported, `RESEND_API` from CC's environment, a self-test value). `12-agent-tooling.md` §5 points at it. | NARROWED — built; the old file's retirement is R-1134 | the week with no reader (R-1134) | `sec doctor` stays all OK; R-1134 | CC | | **R-1121** | Security & access | P3 | **`~/rotated-secrets-2026-10-09.txt` still exists on DooPlex** — 632 bytes, modified 2026-10-09 13:08 +0200, mode 600 (SPIKE Q6: `test -e` + `stat` only, not opened). Left by the R-925 rotation work. If any value in it is still valid, it is one more plaintext secrets file in the home folder, readable by every CC session. | WAITING-ON-OPERATOR | what the file holds — only the operator knows | Operator: confirm every value in it is revoked, then `shred -u` it; or move the live ones into the R-1118 store | operator | -| **R-1130** | Security & access | P3 | **`DOCKER_PASSWORD` is the Docker Hub password of the account `DOCKER_USERNAME`, and it is in one old CC session record** (a helper-agent transcript of 2026-09-21, `~/.claude/projects/-mnt-5-hdd-felhom-eu-git/5f83c0fb…/subagents/agent-a8614eb6ee2a17e6c.jsonl`; first history sweep 2026-10-17). **What it opens, measured 2026-10-17** with a throwaway `DOCKER_CONFIG` (nothing saved): Docker Hub `Login Succeeded`; `gitea.dooplex.hu` **401** (as on 2026-10-08 and 10-10). `~/.docker/config.json` (0600) holds saved logins for Docker Hub — the SAME password (sha256 prefix equal) — and for `gitea.dooplex.hu` (a different 32-character password, 5-character user). Evidence `audits/cc-creds-build-2026-10-17/docker-login-test.txt`. Nothing rotated. | WAITING-ON-OPERATOR | the operator's decision after these facts | Operator: rotate the Docker Hub password or accept; if rotated, `sec put DOCKER_PASSWORD --from-file F` and re-login the saved config | operator | | **R-1133** | Security & access | P3 | **`~/.git-credentials` on DooPlex holds Gitea tokens in clear text** — three entries (`kisfenyo`, `Kisfenyo`, `admin`); the `admin` token has `write:repository` (and misc, package, issue, notification). Any `cat` of it prints them; the new PreToolUse guard refuses reads of that path (`read-secret-file`), but git itself must keep reading it. Out of the 2026-10-17 build's scope by its brief. **Same class:** `~/.docker/config.json` holds two saved registry logins (Docker Hub, `gitea.dooplex.hu`) as base64 — R-1130; the guard does not list that path yet. | OPEN | — | Decide: move git to a credential helper that reads from `sec`, or accept the file (0600) with the guard | operator → CC | -| **R-1134** | Security & access | P3 | **Retire the old `~/.config/credentials`**: every named key is in the CC store since 2026-10-17 13:16 (23 imported; the hyphenated names became `R_DEMO_FELHOM`, `R_DEMO_HP`). The operator added `FACEBOOK_API`, `TUYA_ID`, `TUYA_SECRET`, `TUYA_DEVICE_ID_N100`, `TUYA_DEVICE_ID_HP` to the store the same day; each passed a real read-only call through `sec run` (fb_probe `read`: page, feed, insights ok, token „from environment (sec run)"; Tuya cloud status: both plugs `success`, 18 items). **Open:** its line 20 is a 32-character value with NO name — its sha256 prefix matches NO stored value (`TUYA_SECRET` included; `audits/cc-creds-build-2026-10-17/line20-compare.txt`), so the operator names it. | WAITING-ON-OPERATOR | the operator names line 20; a week with no reader (from 2026-10-17) | 2026-10-24: check no reader (sweep + `hook.log`); then rename the file to `.retired`; delete only on the operator's go | operator → CC | +| **R-1138** | Security & access | P3 | **Two old plain copies of the deleted credentials file remain: `~/.config/credentials.bak-20261001-calibre` (17 keys) and `~/.config/credentials.bak-20261016-tester1` (19 keys)**, both 0600. Compared 2026-10-17 in memory (names only, `audits/cc-creds-build-2026-10-17/old-backups-compare.txt`): every key equals the store except one OLDER value each — `HUB_TOKEN` in the 10-01 copy, `TESTER1_PASSWORD` in the 10-16 copy (both since changed). Found when the operator's go deleted the main file (R-1134); not deleted, because the go named „the file". | WAITING-ON-OPERATOR | the operator's word | Operator: „delete them" → `shred -u` both; or keep | operator | ## Box system & updates — 12 rows (P2 1, P3 7, P4 4) diff --git a/documentation/runbooks/total-loss-of-dooplex.md b/documentation/runbooks/total-loss-of-dooplex.md index b14c335a..13ec8d4c 100644 --- a/documentation/runbooks/total-loss-of-dooplex.md +++ b/documentation/runbooks/total-loss-of-dooplex.md @@ -47,7 +47,7 @@ local restic repos; Prometheus history; DooPlex's other homelab apps (not Felhom | S13 | Domain registrar(s) for `felhom.eu`, `dooplex.hu`; No-IP (`dooplex.hopto.org`, the home address CNAME) | moving DNS / the home address | the operator; Vaultwarden | — | | S14 | Resend account / API key | all mail | Secrets export (S1+S5); Vaultwarden; the Resend dashboard (re-mint) | no — re-mint at Resend | | S15 | Gitea admin password; registry credentials (`gitea-creds`) | Gitea UI; image push/pull | the restored Gitea DB (password hash) + Vaultwarden; the Secrets export | no, after S1 (+S3) | -| S16 | The hub operator password | the hub UI | the restored hub DB (hash); Vaultwarden — NOT `~/.config/credentials` any more (operator-only since 2026-10-15, `09` §3 decision 251; CC holds the scoped token `HUB_TOKEN` there instead, which a restored hub DB keeps as its hash) | no, after S2 (+S3) | +| S16 | The hub operator password | the hub UI | the restored hub DB (hash); Vaultwarden — never in CC's store (operator-only since 2026-10-15, `09` §3 decision 251; CC holds the scoped token `HUB_TOKEN` in its secret store (S19) instead, which a restored hub DB keeps as its hash) | no, after S2 (+S3) | | S17 | Authentik admin | SSO for Vaultwarden and DooPlex apps | Authentik's DB (Longhorn on DooPlex, local PostgreSQL dumps only) | **yes** — not in any copy; Vaultwarden does not need it (password login) | | S18 | Households' recovery codes, PBS keys, restic passwords | households' restores | the households / escrow / the boxes | not the operator's | | S19 | **CC secrets age key** (`~/.config/sops/age/keys.txt` on DooPlex, 0600; public recipient `age1aw83ej37x9sck89xwt856ry0553kf5sng3w544an4et54yjdx5qq79utrv`) | opening `admin/cc-secrets` `store/cc.sops.yaml` — every secret CC uses (`sec`; `cc-secrets/ARCHITECTURE.md`) | DooPlex; Vaultwarden „CC secrets age key" (operator, 2026-10-17); the encrypted store itself is in Gitea (behind S1) | no, after S1 + S3 — unless also on the break-glass sheet | diff --git a/scripts/CHANGELOG.md b/scripts/CHANGELOG.md index 0ec5af2f..5a8aa1ef 100644 --- a/scripts/CHANGELOG.md +++ b/scripts/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2026-10-17 — `~/.config/credentials` deleted (R-1134) + +The operator's go, after every key in it was checked equal in the CC store. `read_credential.py`, `fb_probe.py` and +`bench/README.md` say so; no behaviour change (`--credentials` still reads a given file). + ## 2026-10-17 — the CC secret broker `sec` replaces `~/.config/credentials` for CC (R-1118, R-1122) The tool itself lives in the private repo `admin/cc-secrets` (its own CHANGELOG). Here: the consumers. diff --git a/scripts/bench/README.md b/scripts/bench/README.md index 7cc3b0cf..c8f18482 100644 --- a/scripts/bench/README.md +++ b/scripts/bench/README.md @@ -31,8 +31,8 @@ lifetime total. Use watts × time for energy. When the plug moves address or is paired again: re-run the tinytuya wizard in `~/.config/felhom-bench/` (credentials `TUYA_ID`, `TUYA_SECRET`, `TUYA_DEVICE_ID`, region `eu`) and update `plug.json`. Its output prints the key — send it to a file, never to a terminal or a log. The credentials belong in the CC secret store and are used -through `sec run TUYA_ID,TUYA_SECRET,TUYA_DEVICE_ID -- …` (`admin/cc-secrets`); **they are not in the store yet** — -the old `~/.config/credentials` did not hold them either on 2026-10-17 (R-1118 build). +through `sec run TUYA_ID,TUYA_SECRET,TUYA_DEVICE_ID_N100,TUYA_DEVICE_ID_HP -- …` (`admin/cc-secrets`; the operator added +them 2026-10-17, and a read-only cloud status call through `sec run` passed for both plugs). ## plugswitch.py — switch the N100's plug (`on`, `off`, `status`) diff --git a/scripts/facebook/fb_probe.py b/scripts/facebook/fb_probe.py index d35724ab..bb60e8ad 100644 --- a/scripts/facebook/fb_probe.py +++ b/scripts/facebook/fb_probe.py @@ -15,7 +15,7 @@ There is deliberately NO "post for real" sub-command: real posting belongs to th from this spike's findings (audits/SPIKE-facebook-page-api-2026-10-08.md). SECRETS. The token comes from the CC secret store — run `sec run FACEBOOK_API -- python3 fb_probe.py …` — or, -until the old file retires, from ~/.config/credentials (key FACEBOOK_API); no flag takes one. +from a file given with --credentials (the old ~/.config/credentials was deleted 2026-10-17); no flag takes the token. It travels as `Authorization: Bearer`, never in a logged URL (the one query-string carrier, debug_token's input_token, is never printed: -v prints the path without its query). Every saved response passes redact(): every `access_token` key is dropped and any string carrying a held token diff --git a/scripts/read_credential.py b/scripts/read_credential.py index 4cf9da1b..2a1abc0e 100644 --- a/scripts/read_credential.py +++ b/scripts/read_credential.py @@ -2,7 +2,8 @@ """Read ONE value out of ~/.config/credentials, correctly, and refuse loudly when it is not. SUPERSEDED 2026-10-17 by `sec` (the CC secret store, `admin/cc-secrets` ARCHITECTURE.md): use -`sec run NAME -- `. This reader keeps working until the old file retires (R-1118 follow-up). +`sec run NAME -- `. ~/.config/credentials was DELETED on 2026-10-17 on the operator's go (R-1134), after +every key in it was checked equal in the store; this reader now has nothing to read unless given --credentials. Run: python3 scripts/read_credential.py [--credentials PATH] (OUTFILE is where the value GOES — a temp file. It is refused if it is the credentials file itself.)