Commit Graph
2 Commits
Author SHA1 Message Date
Lubos BuracinskyandClaude Opus 5 9c15f7bf45 fix(redact-prepush): close the remaining shapes of three fail-open classes
Three shapes still exited 0 with a credential in the push.

A push to a URL borrowed origin's tip as its base and excluded every commit
any remote had seen, so a credential already on origin shipped to a new,
empty URL remote unscanned. A URL is described by no remote-tracking ref:
the push target is now a three-way value (configured remote / URL /
unknown), a URL target anchors on nothing and excludes nothing, and an
unknown target keeps the historical origin-shaped behavior.

When git named a remote tip the local clone lacks, only an EMPTY guessed
range was blocked; a stale tracking ref holding the credential plus one
harmless local commit produced a non-empty, credential-free guess that
passed. An absent named tip now gets no local narrowing at all and the
whole reachable history is scanned, which is affordable because every scan
is sliced under the engine's cap.

The inter-slice overlap carried whole lines only, so a line longer than
the overlap contributed nothing and a label at its end never met the secret
at the start of the next slice. The overlap now carries such a line's
suffix.

Gate: test/redact-prepush-fail-open.sh grows to 30 scenarios. E5 expected
the URL-push leak to be ALLOWED and now expects the block, E5b pins that a
clean URL push is still allowed, 19 and 20 pin the other two shapes, and
E8b pins that a clean SHA-256 first push is allowed (E8 carried a
credential, so it could not tell a working empty-tree fix from a broken
one). The S1 URL-push case in redact-prepush-scan-range.test.ts keeps its
no-error assertion and now also asserts the block, because its fixture's
secret really is delivered to that URL.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 18:09:53 +02:00
Lubos BuracinskyandClaude Opus 5 11734707df v1.87.7.0 fix(redact-prepush): four paths where the hook exits 0 on a real credential
Four paths made the pre-push credential scanner exit 0 with the secret going
out anyway, and two adjacent defects in the same functions had to land with
them.

Range resolution: defaultRemoteBranch() asked origin regardless of the push
target, so pushing to a second remote while HEAD matched origin/main resolved
HEAD..HEAD and scanned nothing; and a well-shaped but absent remote sha let a
guessed base's empty diff read as "nothing to scan". The probe is now scoped to
the push target and a guess that scanned nothing blocks with a fetch hint.

Slicing: the no-overlap argument holds for a pattern's match but not for its
proximity requirement, so a label at the end of one slice and its secret at the
start of the next never fired; and budgeting in raw bytes let zero-width
padding decide the seam using bytes the engine strips before matching. Slices
now overlap by 16 KiB and are budgeted in zero-width-stripped bytes.

Adjacent: the fallback range's hardcoded SHA-1 empty-tree id does not exist in
a SHA-256 repository and hard-blocked every legitimate first push there, which
the remote scoping makes reachable more often; and an over-budget single line
was handed to the engine whole, blocking without the content ever being read.

test/redact-prepush-fail-open.sh is the gate: 26 scenarios against real
repositories with synthetic credentials, PASS here and FAIL on the four rows
against the scanner this branch forks from.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 16:14:14 +02:00