Skip to content

cli: the --pre-commit-mode not-examined notice says contents unreadable for every cause, including a budget cut-short and a parse failure #817

Closed

Description

@sectoramen

Summary

In --pre-commit-mode, the one-line stderr notice for files that were not fully examined reads NOT examined (contents unreadable) for every cause, including the two where the tool read the file perfectly well: a validator budget or deadline that cut coverage short, and a file it could not parse. A developer whose commit was let through (rc 0 without --fail-on-incomplete) is told the file was unreadable when the truth is that a validator ran out of time, which points them at the wrong fix (permissions, encoding) instead of the right one (the budget, or --fail-on-incomplete). The entries behind the line already carry the cause; only the wording ignores it. Left in place by #813 because cmd/main.go was outside its files.

Reproduction

Measured on main @ c403e27 (v2.5.5), synthetic input (517-17-1007 is an SSN-shaped test value):

printf 'Ticket 4471: caller verified SSN 517-17-1007, reply to j7.example@example.org\n' > one.txt
ferret-scan --file one.txt --pre-commit-mode --checks SSN,EMAIL --validator-budget all=1ns
# ferret-scan: 1 file NOT examined (contents unreadable) — findings may be missing. Re-run without --pre-commit for detail.
# rc=0
printf '%%PDF-1.7\n517-17-1007\n' > broken.pdf
ferret-scan --file broken.pdf --pre-commit-mode --checks SSN
# ferret-scan: 1 file NOT examined (contents unreadable) — findings may be missing. Re-run without --pre-commit for detail.

Both files were read. The first was cut short by the budget; the second cannot be parsed as a PDF. The full (non-pre-commit) report classifies them correctly as coverage cut short and cannot parse.

Root cause

cmd/main.go:2733–2742: the notice is a single fmt.Fprintf with the literal (contents unreadable) and the entry count. The unscannedEntries it counts come from collectUnscanned (cmd/unscanned_report.go:385), whose entries carry Cause unscannedCause with eight values (causeUnreadable, causeUnparseable, causeNoText, causeCutShort, causeNotFollowed, causeTooLarge, causeNotRegular, causeRefusedTraversal) and a String() label each (:104–125); the full report uses them. The notice was written when the only channel feeding it was the unreadable one, and the wording stayed when the other channels were added.

Resolution

Keep the one-line contract (pre-commit output is read mid-commit) but state the cause: group the entries by Cause and print the labels, e.g. ferret-scan: 1 file NOT examined (coverage cut short) — findings may be missing. Re-run without --pre-commit for detail., or with several causes 2 files NOT examined (1 coverage cut short, 1 cannot parse). When any entry is causeCutShort and --fail-on-incomplete is not set, add the hint that the flag makes this exit 3, since that is the gate decision the developer needs. Reuse unscannedCause.String() so the pre-commit line and the full report cannot disagree.

Acceptance criteria

  • The two commands above print (coverage cut short) and (cannot parse) respectively; a chmod-000 file still prints (contents unreadable).
  • A mixed directory prints the per-cause counts on one line.
  • A test in cmd/ pins the three wordings and fails on main (today's string has no cause).
  • No change to exit codes, to the full report, or to machine formats.

Activity

  1. added this to the v2.6.0 milestone on Oct 24, 2026
  2. added
    bugSomething isn't working
    goPull requests that update go code
    P2Audit tier P2: contained defect or enhancement
    on Oct 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Audit tier P2: contained defect or enhancementbugSomething isn't workinggoPull requests that update go code

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions