From ab2fc21a9c289588a0ec27df8b70045544051e89 Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Sat, 17 Oct 2026 15:10:35 +0200 Subject: [PATCH] CC secrets: R-1138 closed (all old copies shredded, 175 rows); option B; sec run strips unloaded stored names; report Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb --- REPORT-cc-creds-build-2026-10-17.md | 19 +++++++++++++++++++ STATUS.md | 3 +-- .../cc-creds-build-2026-10-17/redproof.txt | 3 +++ documentation/backlog/CLOSED-ITEMS.md | 1 + documentation/backlog/OPEN-ITEMS.md | 3 +-- 5 files changed, 25 insertions(+), 4 deletions(-) diff --git a/REPORT-cc-creds-build-2026-10-17.md b/REPORT-cc-creds-build-2026-10-17.md index 775c7ca4..c241526b 100644 --- a/REPORT-cc-creds-build-2026-10-17.md +++ b/REPORT-cc-creds-build-2026-10-17.md @@ -138,6 +138,25 @@ Register after STOP 3: **181 → 177** (R-1119, R-1120, R-1131, R-1132 closed; R Register: 177 → 176 (R-1130, R-1134 closed; R-1138 opened). +## Last round — the copies, and option B + +- The three old copies of the credentials file are shredded (the operator's word for each); R-1138 closed. +- **Option B** (the operator's choice): inside `sec run`, `bash -x`, `curl -v` and printing a stored name are allowed. +- **A correction and a gap.** I told the operator these shapes were refused inside `sec run`; they were not — the guard + did not check the command after `sec run … --` at all. That also let `sec run X -- cat `, `-- printenv`, + `-- kubectl get secret -o yaml`, `-- sops -d` through, although the mask hides only stored values. Fixed in + cc-secrets 0.2.0: the child is checked as its own command, with only the option-B shapes exempt. Tests red first; + 63 tests, 24/24 red-proofs; live: `sec run X -- bash -x -c true` runs, `sec run X -- sops --version` is refused. +- **A security review of 0.2.0** found that `sec run` masked only the values it loaded, so a stored secret inherited + from CC's environment printed unmasked through option B. Fixed in 0.2.1: `sec run` removes every stored name it did + not load from the child. Live: this session's `RESEND_API` is present in its shell and absent in a `sec run` child. + 64 tests; 25/25 red-proofs. Option B's accepted limits (a traced script reading a file; `curl -v` with a non-stored + credential) are in cc-secrets ARCHITECTURE decision 7. +- **Friction measured** (the operator asked): since the install, 7 refusals, all in this session, 0 in other + sessions (control: the same count finds the 7 here); no real session got a withheld output. + +Register: 176 → 175 (R-1138 closed). + ## 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 a88604db..0fdde25b 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). The old credentials file is deleted (your go). Left: D17, its two old backup copies. +- **CC's secrets** (R-1118): done 2026-10-17 — the store, `sec`, the guards in every CC session (option B: `bash -x` and `curl -v` allowed inside `sec run`), the nightly check (linger on). The old credentials file and its three copies are deleted. - **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,7 +60,6 @@ | 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 | — | — | — | -| D17 | R-1138 | The two dated copies of the old credentials file are deleted. A third, undated one remains: `~/.config/credentials.bak` (all in CC's store, except an older hub token). Delete it too? | **Delete** | Keep: one plain copy of 17 secrets stays on DooPlex | it stays | — | | 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/redproof.txt b/documentation/audits/cc-creds-build-2026-10-17/redproof.txt index d36fa2fc..da5d7352 100644 --- a/documentation/audits/cc-creds-build-2026-10-17/redproof.txt +++ b/documentation/audits/cc-creds-build-2026-10-17/redproof.txt @@ -18,6 +18,9 @@ RED rules: substitutions not looked into -> FAILED (failur RED rules: substitutions skipped under sec run -> FAILED (failures=1) restored=True RED rules: unparseable risky command passes -> FAILED (failures=5) restored=True RED rules: a leading sec run exempts every segment -> FAILED (failures=3) restored=True +RED rules: the child of sec run is not checked -> FAILED (failures=7) restored=True +RED rules: option B not applied -> FAILED (failures=5) restored=True +RED run: unloaded stored names reach the child -> FAILED (failures=1) restored=True RED install: foreign hooks dropped -> FAILED (failures=1) restored=True RED install: malformed settings overwritten -> FAILED (failures=1) restored=True after all restores, full suite: OK diff --git a/documentation/backlog/CLOSED-ITEMS.md b/documentation/backlog/CLOSED-ITEMS.md index 5931541f..668d284c 100644 --- a/documentation/backlog/CLOSED-ITEMS.md +++ b/documentation/backlog/CLOSED-ITEMS.md @@ -45,6 +45,7 @@ | **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` | +| **R-1138** | **Three old plain copies of the deleted credentials file were left in `~/.config/`.** (P3) | CLOSED 2026-10-17 — all three shredded on the operator's word (`.bak-20261001-calibre`, `.bak-20261016-tester1`, then the undated `.bak`); each was compared in memory first: every key equal to the store except one older value each. A final search of `~` (depth 4) finds no `credentials` file outside `~/.claude`. | `audits/cc-creds-build-2026-10-17/old-backups-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 657dc138..bcf60d7d 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 — 21 rows (P1 1, P2 2, P3 12, P4 6) +## Security & access — 20 rows (P1 1, P2 2, P3 11, P4 6) | ID | Category | Sev | What | State | Blocked on | Next action | Owner | |---|---|---|---|---|---|---|---| @@ -235,7 +235,6 @@ stopping line that lies. | **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-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-1138** | Security & access | P3 | **One old plain copy of the deleted credentials file remains: `~/.config/credentials.bak`** (17 keys, 0600, modified 2026-10-16 09:15). The two dated copies (`.bak-20261001-calibre`, `.bak-20261016-tester1`) were shredded 2026-10-17 on the operator's „delete them"; a wider search then found this undated one. Compared in memory (names only): every key equals the store except an older `HUB_TOKEN`. | WAITING-ON-OPERATOR | the operator's word for this third file | Operator: „delete it too" → `shred -u` | operator | ## Box system & updates — 12 rows (P2 1, P3 7, P4 4)