Skip to content

feat: close out the scanner improvement backlog - #115

Merged
pixincreate merged 5 commits into
masterfrom
feat/backlog-107-clean
Sep 14, 2026
Merged

pixincreate merged 5 commits into
masterfrom
feat/backlog-107-clean

Conversation

@pixincreate

Copy link
Copy Markdown
Owner

Implements all five items from #107 in one change, as requested. Item-by-item:

  1. GitHub token checksum validation — classic tokens end in a CRC32 of their 30 random characters, base62-encoded, zero-padded to six. The validator computes it offline, so lookalike strings survive 1 in 62^6 times. Verified against a live token; GitHub's published example token is fabricated and does not self-validate. Non-36-character bodies pass unchecked so a future format is not silently dropped. Amusing side effect: GitHub push protection validates the same checksum, so the checksum-valid test fixture had to be assembled with concat! to be pushable at all.
  2. UTF-16 support — files and staged blobs starting with a byte-order mark are decoded (both byte orders) and scanned; Windows-written .env files were previously skipped as binary. BOM-less UTF-16 stays classified as binary on purpose.
  3. Base64 decoding — runs of 24+ characters are decoded and the text is scanned once (no recursion), attributed to the original line. Decoded content must be printable text of 16+ bytes, so digests and compressed data are rejected before any detector runs. A test also pins that JSON-escaped private keys were already caught by the multiline detectors.
  4. Flag split--trusted-detectors and --no-repo-config separate the two behaviors of --no-config-discovery, which remains as their combination so installed hooks keep working unchanged.
  5. --max-file-size <MB> — larger files and staged blobs are reported as unscannable rather than scanned; visible to --fail-on-unscannable. No default limit: silently skipping content is worse than a slow scan unless asked for.

271 tests pass, clippy clean, self-scan clean, baseline stable under repeated regeneration.

Closes #107.

Implements the five items tracked in #107:

- GitHub classic tokens (ghp_/gho_/ghu_/ghs_/ghr_) are validated
  against their built-in CRC32 checksum: base62 over the 30 random
  characters, zero-padded to six. Verified against a live token;
  GitHub's published example token is fabricated and does not
  self-validate. Non-36-character bodies pass unchecked so a future
  format is not silently dropped. The checksum-valid test fixture is
  assembled with concat! because GitHub push protection validates the
  same checksum and rejects the contiguous literal as a live token.

- UTF-16 files and staged blobs that start with a byte-order mark are
  decoded (both byte orders, lossily) and scanned; Windows-written
  .env files were previously skipped as binary. BOM-less UTF-16 stays
  classified as binary: without the mark, distinguishing it from a
  real binary is guesswork.

- Base64 runs of 24+ characters are decoded and the decoded text is
  scanned once more (no recursion), attributed to the original line.
  Decoded content must be printable text of at least 16 bytes, so
  digests and compressed data are rejected cheaply. Inline
  suppression stays a property of the visible line.

- --trusted-detectors (ignore repository detector files) and
  --no-repo-config (skip .keywatch.toml discovery) split the two
  behaviors of --no-config-discovery, which remains as their
  combination so installed hooks keep working unchanged.

- --max-file-size <MB> reports larger files as unscannable instead
  of scanning them, visible to --fail-on-unscannable; staged blobs
  respect the same cap. No default limit: silently skipping content
  is worse than a slow scan unless the operator asked for it.

Closes #107.

Assisted-by: Claude Fable 5
Signed-off-by: PiX <69745008+pixincreate@users.noreply.github.com>
- The reported_by helper and three sibling closures gated matches with
  accepts_match (whole match), while production gates the captured
  value with accepts_captures. No fixture was falsely green, but a
  future fixture could have blessed a detector the scanner never
  fires. All helpers now mirror the production accept chain exactly.
- The unlistable-directory tests print a SKIPPED notice when running
  as root, where mode 000 cannot construct the scenario, instead of
  passing silently while verifying nothing.
- Existence-only assertions became exact: the multi-secret line pins
  its full finding list, the Aadhaar test pins exactly one finding,
  and the PEM header test names SSHPrivateKeyDetector.
- README corrections: --fail-on-unscannable documents its strict-mode
  and --update-baseline limits again, the pre-push hook section says
  only HIGH/CRITICAL findings block (critical exit mode), the SARIF
  example writes to a file, and the staged multi-hunk limitation note
  is restored.
- New coverage: an end-to-end pre-push test proves remote..local range
  semantics with the real binary against real commits (a historical
  secret outside the range does not block; the same commit inside the
  range does), and a CLI-level SARIF test validates the written
  report's version, ruleId, level and location.

Assisted-by: Claude Fable 5
Signed-off-by: PiX <69745008+pixincreate@users.noreply.github.com>
Pad the option, exit-code, hook and Action tables to aligned columns,
and add notes for the behaviors this branch introduces: UTF-16 files
with a byte-order mark are decoded and scanned, base64 runs are
decoded and rescanned at their original line, and GitHub tokens are
checked against their built-in checksum.

Assisted-by: Claude Fable 5
Signed-off-by: PiX <69745008+pixincreate@users.noreply.github.com>
The plain-language rewrite dropped the architecture diagrams and their
explanations, keeping only a pointer to docs/architecture. The images
carry real orientation value, so the section returns with the diagrams
and the explanations rewritten in the same plain style as the rest of
the file.

Assisted-by: Claude Fable 5
Signed-off-by: PiX <69745008+pixincreate@users.noreply.github.com>
The scan pipeline gained UTF-16 decoding, the file size cap, content
validators and the base64 rescan stage, and the trust diagram still
described trusted mode as one flag after --trusted-detectors and
--no-repo-config split it. Both sources are updated and re-rendered
with the pinned D2 v0.7.1; the module diagram is unchanged because
nothing moved at that level. The baseline covers the re-rendered
SVGs' shifted font data.

Assisted-by: Claude Fable 5
Signed-off-by: PiX <69745008+pixincreate@users.noreply.github.com>
@pixincreate
pixincreate merged commit 3b9c884 into master Sep 14, 2026
7 checks passed
@pixincreate
pixincreate deleted the feat/backlog-107-clean branch September 14, 2026 17:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Planned scanner improvements

1 participant