repo-manager/docs/secret-detection.md
tegwick 21498306ec security: enforce staged secret scanning on reviewed workstation checkouts
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a12d13-27f2-7163-b8c0-f682af02772c
2026-10-12 17:47:19 +02:00

108 lines
6.1 KiB
Markdown

# Repository secret detection
Repo Manager provides a control adapter to an external scanner. Credential
custody, incident response and authorization remain with their existing owners.
The adapter does not itself install hooks. The reviewed workstation activation
below composes it with the existing generated-only guard.
Work: RMGR-WP-0021, coordinated by Custodian CUST-WP-0080 G07.
## Scan the proposed index
```bash
rmgr secret-scan --path /path/to/repo --binary /reviewed/path/to/gitleaks
```
The supported executable is Gitleaks 8.30.1 Linux x64, SHA256
`88f91962aa2f93ac6ab281d553b9e125f5197bbbce38f9f2437f7299c32e5509`.
Install/admit it separately; this command never downloads or executes an
unverified replacement. The reviewed test archive and checksum came from the
[official release](https://github.com/gitleaks/gitleaks/releases/tag/v8.30.1).
Checksum comparison alone is not a detached signature verification or fleet
installation receipt. Other platforms/versions need an explicitly reviewed pin.
The JSON result contains a fixed status, counts and affected Git blob IDs. It
contains no findings, paths, matched lines or credential values. Raw scanner
stdout/stderr are discarded even on errors; no findings report is written.
Inspect blocked content only in an approved private review environment. Never
paste it into chat, State Hub, issue bodies or CI logs.
| Exit | Result | Required caller behavior |
| --- | --- | --- |
| 0 | `clean` | No detection in the declared changed staged blobs |
| 1 | `blocked` | Reject the proposed commit and privately review the indicated objects |
| 2 | `unverified` | Reject; fix missing tool, unreadable index, limits or other verification failure |
`clean` is not a statement about working-tree files, existing HEAD/history, other
branches, remote refs, logs, artifacts, production credentials or complete absence
of secrets. An empty staged change scans zero objects and says nothing about
history. The scanner uses the upstream default detection rules; heuristic false
negatives and false positives remain possible.
## Input and configuration boundaries
The adapter scans complete changed staged blobs, including an initial commit,
renames and partial staging. It honors Git's explicit alternate index (including
`git commit --only` behavior), ignores Git replacement objects and refuses index
changes observed during scanning. Symlink text is scanned without reading the
external target. Changed gitlinks, conflicts and unreadable entries are refused.
A reviewed configuration extending the scanner's built-in defaults is supplied
from an isolated temporary directory. Repository `.gitleaks.toml`, ignore files,
inline `gitleaks:allow` comments and ambient scanner environment do not suppress
this check. There is no implicit baseline or exception switch. False positives
need a reviewed follow-up mechanism with exact scope and real approval; do not
silently add broad path exclusions.
The current resource bounds are 500 distinct blobs, 8 MiB per blob and 64 MiB in
total; exceeding a bound refuses instead of skipping. Individual Git and scanner
calls have timeouts. The executable is hash-checked and invoked through its open
file descriptor. These measures are not isolation from a hostile same-UID writer,
a malicious Git installation, hook bypass or a process with repository authority.
## Enforcement and response acceptance
Before activating a hook, preserve the existing generated-commit and assistant
provenance checks; validate exact repository coverage, executable availability,
clean commits, synthetic detections and scanner failures. Do not replace the
shared hook or change global `core.hooksPath` merely to run this command.
Local pre-commit can be bypassed. Forge/CI enforcement must independently check
all introduced objects/commits, including merge/base-history cases and unavailable
scanner failures. Required checks and writers able to alter enforcement need
separate admission. An actual finding needs owner classification and a governed
revocation/rotation path; source removal or rejection of one commit does not
revoke credentials that were already exposed. CUST-WP-0073-T05's existing founder
deferral is not overridden by this adapter.
## Verified workstation activation (2026-10-12)
The shared `.githooks/pre-commit` composes the existing Custodian generated-only
guard with the scanner for these exact `/home/worsch/` checkout names:
access-engine, approval-engine, audit-core, gate-house, glas-harness, key-cape,
kings-guard, maturity-engine, net-kingdom, ops-mason, ops-warden, policy-nexus,
railiance-forge, railiance-platform, repo-manager, role-engine, secrets-engine,
security-canon, tenant-engine, the-custodian, user-engine and zone-engine.
Custodian's separately configured local pre-commit has the same composition.
Other checkout paths retain their existing generated-only behavior.
The admitted binary is `/home/worsch/.local/lib/repo-manager/gitleaks/8.30.1/gitleaks`.
All 22 configured hooks passed clean, disposable-key rejection, generated-only
rejection and unavailable-scanner refusal checks. The failure probe restored the
binary mode. Other hooks and Git routing were preserved. These are actual hook
invocations with temporary Git indexes/object stores, not pushes to a forge.
Custodian stores the exact proposal, backups and rollback executor under
`docs/changes/CUST-WP-0080/`, and the native receipt under
`docs/evidence/2026-10-12-netkingdom-security/secret-hook-activation.json`.
The generated-guard installer recognizes the exact reviewed composition without
replacing it. Rollback restores the prior hook bytes/modes after revision checks;
the binary remains installed but inert. Clones on other machines are not covered.
Independent forge/CI and finding-to-response acceptance remain RMGR-WP-0021-T03/T04.
## Tests
Set `RMGR_TEST_GITLEAKS` to the exact reviewed test executable when running
`pytest tests/test_secret_scan.py`. Tests use disposable repositories and keys,
verify commit refusal and preserved index semantics, and never contact a forge
or issuer. Without the test executable, scanner-dependent tests explicitly skip;
those skips are not acceptance evidence.