Security - caveman-savings¶
Threat model¶
Both scripts run locally, unattended, with the operator's own privileges, against the
operator's own ~/.claude configuration directory. There is no network listener, no
outbound network call, no subprocess execution of untrusted input, and no credential of any
kind read, written, or required. The realistic risk surface is limited to:
- accidental data loss in
~/.claude/CLAUDE.mdor~/.claude/settings.jsonfrom a bad write (mitigated: idempotent read-modify-write with a.bakbackup before everysettings.jsonwrite, and in-place marker-fenced block replacement forCLAUDE.md); - accidental cross-project backup collision in
Migrate-CavemanBackups.ps1's attribution logic (mitigated: ambiguous cases are left untouched and warned about rather than guessed).
Secrets handling¶
There are no secrets in this repository, by design - neither script needs to authenticate to
anything. The hard secret-grep gate
(council_[a-z0-9]{20,}|Bearer [A-Za-z0-9._-]{12,}|AKIA[0-9A-Z]{16}|sk-[A-Za-z0-9]{20,}|gh[pousr]_[A-Za-z0-9]{20,}|xox[baprs]-[A-Za-z0-9-]{10,}|-----BEGIN [A-Z ]*PRIVATE KEY-----)
was run over the full working tree (scripts/, tests/, docs/, this file) before every
commit and returned no matches. A Pester test (No hardcoded secrets in
tests/CavemanSavings.Tests.ps1) also asserts neither script contains a bearer-token,
sk-, AKIA, or PEM private-key literal, so a future accidental addition fails CI, not just
a pre-commit grep.
Scan results summary¶
| Scan | Result |
|---|---|
| Secret grep (hard gate) | Clean - no matches in scripts/, tests/, or docs/ |
Codex security review (codex exec over the repo) |
No secrets/RCE found. 4 CI-template findings (below); see docs/MAKING-OF.md chapter 1 for the verbatim verdict |
Semgrep (semgrep scan --config auto --error ., via Docker, CI security job) |
Runs on every push/PR |
Codex findings (none block the ship gate - no secret or RCE finding)¶
- HIGH -
ci.ymlrunspull_requeston a non-ephemeral self-hosted runner. This is the house-standard CI template (identical inhouse-council-client), mitigated by the repo being private with house-member-only contributors, as noted in the workflow's own supply-chain comment block. Accepted at the fleet level, not specific to this repo. - MEDIUM -
docker run semgrep/semgrepuses a floating:latesttag rather than a digest pin. Same as the pilot template. Left as-is to match the house CI template exactly; worth revisiting fleet-wide (not per-repo) if the org migration adds an image-mirroring step. - MEDIUM - the Pester bootstrap step trusts PSGallery and installs with
-SkipPublisherCheck. Same as the pilot template - CI-bootstrap-only, does not affect the shipped scripts. - LOW -
Apply-CavemanSavings.ps1discoverscompress.pyunder the (mutable) local plugin cache and runs the firstpythononPATH. Local-machine-only, no network involved; an operator with a poisoned plugin cache orPATHalready has arbitrary code execution on their own machine regardless of this script. Tracked as a backlog item indocs/BOARD.md(make the compress command injectable/overridable) rather than fixed here.
Supply chain¶
.github/workflows/ci.ymlpinsactions/checkoutto a full commit SHA (11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2), not a mutable tag.- No third-party PowerShell modules are required to run either script - only Pester (a well-known, widely-vetted test framework) is required to test them, and only in CI/dev.
- Semgrep runs via the official
semgrep/semgrepDocker image (no native Windows binary exists), so the CI runner never installs an unaudited pip package for this.