diff --git a/HANDOFF.md b/HANDOFF.md index a8d3296..6783cba 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -251,7 +251,13 @@ Zombie entities deleted from the registry: `script.leak_strobe`, `script.doorbel - The judder reproduction take in the FAILING geometry (vertical 1080p60 first) is still outstanding — no fix until a take names the stage. - ⛔ Sudo password rotation pending (user; then update both `CREDENTIALS.md` password lines). -- TASK 56 secret scan before `gramps/LlamaCasty` goes public. +- ✅ **TASK 56 secret scan — DONE 2026-10-22, CLEAN.** 432 reachable commits (all branches, 35 + tags, reflog, stash) + 63 dangling commits + the worktree: **0 real secrets**. 4 rule hits, all + false positives (`README.md:79` = the `your-client-secret` doc placeholder; + `TokenStoreTests.cs:22` = a 9-char test dummy). `CREDENTIALS.md`/`MARCOM.md`/ + `Helpers/OAuthCredentials.cs` were never tracked. ⚠️ the repo was **already public** (anonymous + GET → 200, API `private = false`) when the scan ran — the gate came late, but nothing leaked. + Method + verdict: `TASKS/task-56-secret-scan.md`. - TASK 55 disk hygiene (`startup.log` uncapped — 23MB and growing every 5s). ## Tests diff --git a/MyMistakes.md b/MyMistakes.md index d8fe151..15a859b 100644 --- a/MyMistakes.md +++ b/MyMistakes.md @@ -2274,3 +2274,27 @@ settled the design in one run. **Probe, then code** — this is not in any WPF b sizes to its **content**, not to the ComboBox — measured 142.7px of popup for a 100px ComboBox whose rows read "swatch + hex + name". A long row is never clipped, and the popup may be wider than the closed box. Measure with `ActualWidth` in a throwaway test; do not guess widths. + +## 2026-10-22 — SCANNING A GIT HISTORY FOR SECRETS WITHOUT EVER PRINTING ONE (RECIPE) + +A release gate ("the repo goes public — check the history first"). The rule from +`MyMistakes.md` → "NEVER PRINT CREDENTIALS.md" applies to the SCAN too: a matched value must +never reach the screen, the transcript, or a log file. + +**The pipeline:** `git log --all --reflog -p --unified=0 --format='@@@%H'` piped into a matcher +that prints **only `sha | path | rule`**. Three details that decide coverage: +- `--all` covers every branch and tag; **`--reflog` is not optional** — a commit that was + `reset` away is still reachable by SHA, so it is still exposed; `refs/stash` comes along too. +- **`git fsck --unreachable`** lists the dangling commits no ref points at. They are in the + object store and recoverable by SHA, so scan them (`git show -p ` per SHA). +- The current file comes from the `+++ b/` line; without it every hit is unattributable. + +**A rule match is a LEAD, not a finding — classify it without printing it:** compare the match +against known placeholders (`your-client-secret`) and test-marker words (`test`, `dummy`, `fake`, +`example`) and print only the verdict + length. In this repo's scan, 4 hits were all +false positives (a doc placeholder and a unit-test dummy) and 2 real secrets were not present — +so the honest report was "4 hits, all false positives", not "4 leaks". + +**Never print a matched value — but still say WHAT it is.** The report format that satisfies both: +commit + path + line + rule + verdict. "README.md:79 | assigned-credential | placeholder" is +actionable; the same report without the verdict forces the reader to go look at the secret. diff --git a/TASKS.md b/TASKS.md index 71590ef..4e3afc9 100644 --- a/TASKS.md +++ b/TASKS.md @@ -71,7 +71,7 @@ | 53 | **Output-format verification: Shorts/TikTok geometry (9:16)** | ☐ Queued (2026-10-08) — output formats never tested end-to-end; pin + prove the vertical geometry | [`TASKS/task-53-output-formats.md`](TASKS/task-53-output-formats.md) | | 54 | **Marcom round: free-forever positioning + merch storefront** | 🔶 In progress — llamacasty.com copy live 2026-10-08 (pricing stripped); merch POD + app About links queued | [`TASKS/task-54-marcom-free-merch.md`](TASKS/task-54-marcom-free-merch.md) | | 55 | **Disk hygiene: log rotation + low-disk guard** | ☐ Queued (2026-10-09) — `startup.log` appears uncapped; also temp alert-clip cleanup + free-space check before recording | [`TASKS/task-55-disk-hygiene.md`](TASKS/task-55-disk-hygiene.md) | -| 56 | **Pre-publication secret scan (full git history)** | ☐ Queued (2026-10-09) — gate before the Gitea repo goes public; report commit/path only, never values | [`TASKS/task-56-secret-scan.md`](TASKS/task-56-secret-scan.md) | +| 56 | **Pre-publication secret scan (full git history)** | ✅ Done — 2026-10-22, **CLEAN** (432 reachable commits + 63 dangling + worktree; 4 hits, all false positives: a `your-client-secret` doc placeholder and a test dummy — nothing to rotate). ⚠️ the repo was **already public** when the scan ran (anonymous GET → 200), so the gate came late — but nothing was exposed | [`TASKS/task-56-secret-scan.md`](TASKS/task-56-secret-scan.md) | | 57 | **Vertical (9:16) tier camera placement — the "vv" feature** | ✅ **Both units shipped 2026-10-21** (Unit 1 = Live scene: own placement per tier — small tile, circle-or-rect, one of six spots; drag-snap + manual entry; 16:9 restored exactly. Unit 2 = Chat scene: rect only — the circle is not offered — the tile or one whole 607×540 area) | [`TASKS/task-57-vertical-camera-layout.md`](TASKS/task-57-vertical-camera-layout.md) | | 58 | **Properties-panel style consistency (the theme owns the look)** | ✅ Done — 2026-10-21 (the creator's "why is the drop-down not in the same style as the others?" — the drop-downs/fields/check boxes had been hand-painted instead of themed, so WPF drew the light system template; now every one carries a theme style, guarded by a test) | [`TASKS/task-58-properties-style-consistency.md`](TASKS/task-58-properties-style-consistency.md) | | 59 | **The properties panel is a hierarchy (titles own their content)** | ✅ Done — 2026-10-21 (the creator's ruling: a "Shape" title above the Mirror/Rect row, the drag hint indented under it, the same for Geometry / Border Color / Border Thickness, Remove + Blur under Background, Strength under Blur — and the shape became a CHOICE: Rect | Circle with Rect selected by default) | [`TASKS/task-59-properties-hierarchy.md`](TASKS/task-59-properties-hierarchy.md) | diff --git a/TASKS/task-56-secret-scan.md b/TASKS/task-56-secret-scan.md index 1e17cf8..5c2920f 100644 --- a/TASKS/task-56-secret-scan.md +++ b/TASKS/task-56-secret-scan.md @@ -1,4 +1,4 @@ -# TASK 56 — Pre-publication secret scan of the full git history (queued 2026-10-09) +# TASK 56 — Pre-publication secret scan of the full git history (✅ done 2026-10-22) > Catalog: [`TASKS.md`](../TASKS.md) — status and requirements live here. @@ -11,13 +11,51 @@ past commit becomes readable too. Anything ever committed by mistake would be ex **Slices:** -1. ☐ **Scan every commit, every branch** for secret-shaped content: Google OAuth client secrets +1. ✅ **Scan every commit, every branch** for secret-shaped content: Google OAuth client secrets (`GOCSPX-`), API keys / tokens (Polar OAT, `ghp_`, `AKIA`, private-key headers), passwords, stream keys, and any once-tracked `CREDENTIALS.md` / `OAuthCredentials.cs`. ⛔ **Report commit + path + rule only — never print a matched value** (see `MyMistakes.md` → "NEVER PRINT CREDENTIALS.md"). A tool like gitleaks with `--redact`, or `git log -p` piped to a counter, never to the screen. -2. ☐ **If anything is found:** rotate that secret first (it's burned regardless), then decide with +2. ✅ **If anything is found:** rotate that secret first (it's burned regardless), then decide with the creator: rewrite history (`git filter-repo`) vs. accept the rotated value staying in history. -3. ☐ Record the result (clean / what was rotated) here and in `HANDOFF.md`, then the creator flips - the repo public. + **Nothing was found → nothing to rotate.** +3. ✅ Record the result (clean / what was rotated) here and in `HANDOFF.md`. + +## RESULT — 2026-10-22: CLEAN (0 real secrets) + +**Coverage:** 432 reachable commits (all branches, all 35 tags, the reflog and `refs/stash`) + the +63 unreachable commits `git fsck` still holds + every tracked file in the worktree. + +**Findings: 4 hits, all false positives** (report = commit + path + rule only, no values printed): + +| commit | path | rule | verdict | +|---|---|---|---| +| `4e42871` | `README.md:79` | assigned-credential | **placeholder** — the doc snippet `ClientSecret = "your-client-secret"` | +| `4afe11e` | `ytLive.Tests/TokenStoreTests.cs:22` | assigned-credential | **test fixture** — a 9-char dummy access token | +| WORKTREE | `README.md:79` | assigned-credential | same placeholder, still in the tree | +| WORKTREE | `ytLive.Tests/TokenStoreTests.cs:22` | assigned-credential | same test dummy, still in the tree | + +**Nothing to rotate. No history rewrite needed.** `CREDENTIALS.md`, `MARCOM.md` and +`Helpers/OAuthCredentials.cs` were **never tracked** (they are in `.gitignore`, and no commit +ever added them) — the "once-tracked secret file" rule matched nothing. + +⚠️ **The gate was blown before the scan ran:** the repo is **already public** — an anonymous +`GET https://llgit.llamachile.tube/gramps/LlamaCasty` returns **HTTP 200**, and the API reports +`private = false`. The scan came back clean, so nothing was exposed; the ordering was simply +late. The creator still owns the decision to keep the repo public. + +## The method (reusable — the scan is a one-liner over `git log -p`) + +```bash +# pipe the history into a matcher; print ONLY sha + path + rule, never the matched text +git log --all --reflog -p --unified=0 --format='@@@%H' | +``` +- `--all` = every branch + tag; `--reflog` also covers commits that were reset away (they are + still recoverable by SHA, so they count); `refs/stash` is included via `--all`. +- `git fsck --unreachable` lists the **dangling** commits no ref points at — scan those too + (`git show -p ` per SHA). +- Track the current file (`path`) from the `+++ b/` line and attribute each hit to it. +- **Classify a hit without printing it**: compare it against known placeholders + (`your-client-secret`) and test-marker words (`test`, `dummy`, `fake`, `example`), and print + only the verdict + length. A rule match is a *lead*, not a finding.