fix(redfix): SECURITY — redact live Gitea bot password from machine-docs/BACKLOG-redfix.md

Commit 2ad38f5 (review(redfix) re-confirmation #17) added an A-redfix-1 "repro" line that inlined the
ACTUAL autonomic-bot Gitea password as a grep pattern, and it was pushed to origin/main. Redacted at
HEAD: the repro now greps 'autonomic-bot:' instead, verified to return the same result (1), so the
finding loses no verifiability.

This ESCALATES A-redfix-1: the secret moved from one 0644 file on one host (reachable only from pid1's
mount ns) into a git repo replicated to every clone and readable by anyone with mirror access — and the
credential grants push to recipe-maintainers/*, so it now sits inside a repo it can write to.

Redaction stops propagation; it does NOT undo disclosure. The secret is in history at 2ad38f5, and
excising it needs a history rewrite + --force, which the standing rules forbid. => The autonomic-bot
password MUST be rotated by the operator (Class-A1 external input, plan §4.4). Filed as B-redfix-8.

No DoD item is touched; the phase is not reopened. DONE stands.
This commit is contained in:
2026-07-09 01:55:28 +00:00
parent e64d8e7441
commit d07873a276

View File

@ -109,6 +109,28 @@ hold). Concrete fix designs from M1 evidence:
to a `credential.helper` / netrc outside the repo; (c) if the clone is genuinely orphaned, remove it and
let Nix own any needed checkout. Rotating the bot password is worth considering regardless, since it has
sat in cleartext on disk.
- [ ] **B-redfix-8 — the live Gitea bot password was committed to this repo and pushed to `origin/main`**
(**OPERATOR ACTION NEEDED — rotation is now the only real remediation**; found + redacted wake #19).
While documenting A-redfix-1, `machine-docs/BACKLOG-redfix.md` gained a "repro" line that inlined the
**actual bot password** as a `grep` pattern. Introduced by commit **`14c7dee`**, which is **on
`origin/main`** — i.e. pushed to `git.autonomic.zone/recipe-maintainers/cc-ci`.
**This strictly escalates A-redfix-1.** That finding was a secret in one 0644 file on one host,
reachable only from pid1's mount namespace. This moved the same secret into a **git repository**, which
is: replicated to every clone (both loops' clones and the node's `/etc/cc-ci`), readable by anyone with
read access to the mirror, and — the sharp edge — the credential grants **push** access to
`recipe-maintainers/*`, so it now sits inside a repo it can write to.
**Done:** redacted from `HEAD` (wake #19); the repro now greps `autonomic-bot:` instead, verified to
return the same `1`, so the finding lost no verifiability.
**NOT done, and cannot be by me:** the secret remains in **history at `14c7dee` forever**. Excising it
needs a history rewrite + `--force`, which the standing rules forbid ("Never `--force`"), and which
would break both loops' clones. Redaction at HEAD stops propagation; it does **not** undo disclosure.
**⇒ Rotate the `autonomic-bot` Gitea password.** It was already advisable under A-redfix-1; it is now
mandatory, and it is a Class-A1 external input, so only the operator can do it. Once rotated, `14c7dee`
becomes inert and no rewrite is needed. The re-issued credential must NOT go back into a remote URL —
see A-redfix-1's remedy ladder (`credential.helper` / netrc outside the repo).
**Process lesson (mine):** my pre-commit guard did catch this, but I had chained it with `;` instead of
`&&`, so the commit proceeded anyway and I pushed on top of the leak. A guard whose failure does not
halt the pipeline is decoration. Fixed by making the check `&&`-gated before `git commit` in wake #19+.
## Adversary findings
@ -123,7 +145,9 @@ severity *rationale* is right, because the wrong rationale would let the mitigat
**Repro (read-only, from any shell with `ssh cc-ci`):**
stat -c '%a %U:%G %n' /etc/cc-ci/.git/config # -> 644 root:root
grep -c '***REDACTED-ROTATED-CREDENTIAL***' /etc/cc-ci/.git/config # -> 1 (cleartext bot password in origin URL)
grep -c 'autonomic-bot:' /etc/cc-ci/.git/config # -> 1 (cleartext bot password in origin URL)
# [REDACTED by Builder, wake #19] the line above originally inlined the LIVE bot password as the
# grep pattern. Matching on the username is an equivalent repro and leaks nothing. See B-redfix-8.
stat -c '%a %n' / /etc /etc/cc-ci /etc/cc-ci/.git # -> 755 on every parent: world-traversable
**Why LOW — the correct reason.** B-redfix-7 argues "no non-root *login* users exist (no uid>=1000 with a