This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

TruffleHog rules

Scan-only Bazel tests with commit-and-line finding allowlists

Scan state machine with policy validation, finding classification, and pass, unmatched, or error outcomesScan state machine with policy validation, finding classification, and pass, unmatched, or error outcomes

StateDetails
Scan Git historyScan HEAD history by default, or all local refs on request. Inline ignores apply only to the revision containing them.
Exit statusRaw scanner status: 0 without findings, 183 with findings. Other statuses fail validation.
Read stdoutProcess findings while the scanner runs, continuing through buffered output until EOF.
Apply allowlistMatch detector, path, full commit ID, and line. Preserve original JSON, including suppressed findings.
Validate scanWait for both stdout EOF and process exit, then check the exit status against finding counts. Any error fails the scan.

rules_trufflehog is a standalone Bazel module with a reusable test rule and Go scan wrapper. It redeclares existing repository dependency pins. Git metadata uses TruffleHog’s generated protobuf Go type at the scanner’s 3.99.7 pin. The surrounding CLI output uses ordinary Go JSON, so the wrapper keeps a small envelope adapter and retains complete original JSON findings. The module owns the scanner release pin and binary toolchain. The consumer supplies a Git executable, repository marker, and policy. The monorepo’s scan targets and allowlist live in tools/trufflehog. The state-machine source is rendered through the shared site pipeline.

load("@rules_trufflehog//:defs.bzl", "trufflehog_test")

trufflehog_test(
    name = "secrets_test",
    git = ":git",
    repository_marker = "//:AGENTS.md",
    allowlist = "allowlist.json",
)

The default scanner is @rules_trufflehog//:trufflehog, selected through the module’s registered execution-platform toolchain. The module registers every toolchain generated from its lock; archive execution constraints select a compatible implementation without another registration in the parent repository. The existing release archive supports Linux x86-64. The binary lock owns its version and integrity; the generated Go metadata uses the same version. Pass scanner only for a custom binary or a controlled test fixture. Its executable and runfiles replace the default scanner. The public CLI target can also run directly. This module requires Bazel 9.3.1 or later, matching its binary-toolchain dependency.

The marker must be a file at the Git worktree root. The rule resolves its real location, merges tool runfiles, and runs without generated shell glue. HEAD history is the default; all_refs = True includes every local ref. Both modes disable credential verification and update checks and bypass cached test results. They do not scan uncommitted or untracked source. Inline trufflehog:ignore comments apply to the revision containing them. Adding an ignore now does not suppress a finding in an earlier commit.

The JSON policy uses schema trufflehog_allowlist/v1 and a findings array. Each entry contains detector, path, commit, line, and reason. All coordinates must match the scanner result exactly. Commit IDs must be full lowercase Git object IDs; lines must be positive. Paths are canonical repository-relative Git paths. Reasons must be nonempty.

There are no value hashes, regex matches, mutable refs, or abbreviated commits. Duplicate tuples and unknown policy fields fail before starting the scanner. A tuple covers results from that detector at the specified immutable source line. Findings in a different commit or at another line remain actionable. An entry absent from a branch’s history is valid; stale entries do not fail a scan.

The wrapper writes newline-delimited JSON finding events containing the complete original result and a suppressed flag, followed by total, suppressed, and unmatched counts. Approved findings remain available for local inspection. Scanner diagnostics pass through stderr. Keep original reports in restricted local storage rather than publishing credential values in a PR.

TruffleHog’s raw exit status must be 0 without findings or 183 with findings. The wrapper checks it after reading stdout through EOF; any other status or contradictory finding count fails the scan.

The wrapper returns zero only after a complete scan with no unmatched findings, 183 for unmatched findings, and 1 for policy, execution, or decoding errors. A scanner error remains an error when every decoded finding is approved. Both modes always pass --no-verification, --no-update, and --fail-on-scan-errors.

Use @rules_trufflehog//cmd/scan:scan -- --help for direct flags, or //cmd/scan:scan from the standalone workspace. Direct invocations require caller-owned TMPDIR; Bazel tests use TEST_TMPDIR. The E2E command fixture produces e2e-report.json in undeclared test outputs. rule_test exercises the native rule and runfiles wiring; the repository consumer exercises the pinned scanner over real history. Maintained work lives in this project’s OpenSpec workspace. The shared Bazel configuration is imported through .bazelrc. The repository CLI alias in tools/trufflehog forwards to the module-owned binary. There is no root third-party scanner package or separate release pin.

1 -

Scan-only TruffleHog tests with exact historical finding allowlists.

load("@rules_trufflehog//:defs.bzl", "trufflehog_test")

trufflehog_test(name, git, repository_marker, allowlist, scanner, all_refs, tags, **kwargs)

Runs a fresh Git-history scan without credential verification.

PARAMETERS

NameDescriptionDefault Value
nameTest target name.none
gitConsumer-supplied Git executable.none
repository_markerFile at the worktree root.none
allowlistJSON policy with exact detector/path/commit/line tuples.none
scannerOptional executable override for a custom scanner or fixture.Label("@rules_trufflehog//:trufflehog")
all_refsInclude all local refs when true.False
tagsAdditional tags, such as manual for an all-ref audit.[]
kwargsCommon Bazel test attributes.none

2 - TruffleHog wrapper command acceptance

These failure cases are defined before implementation:

  • Only an exact detector/path/commit/line tuple succeeds; each changed coordinate and a second unmatched finding must fail without hiding the original records.
  • A new commit at the same path and line must not inherit an older suppression.
  • Unknown policy fields (including value hashes), malformed or abbreviated commit IDs, invalid paths, nonpositive lines, missing reasons, and duplicate entries fail.
  • Truncated JSON, missing finding metadata, scanner launch failures, timeout, scanner errors after approved output, and contradictory scanner exit codes fail.
  • The scanner must receive --no-verification, --no-update, and error-failure flags. HEAD mode skips additional refs; all-ref mode scans all local refs.
  • Zero findings succeed; fully approved findings retain original values and counts.
  • The E2E test invokes the built wrapper and a controlled scanner subprocess, exercising the pinned JSON protocol without contacting credential services. It writes e2e-report.json to Bazel’s undeclared test outputs. The repository consumer separately exercises the real pinned scanner over Git history.

Scanner-ownership acceptance is defined before changing the rule API:

  • Repository scan targets omit scanner and execute the module-owned pinned binary through its default toolchain; the retained scan report proves runtime use.
  • The standalone build fixture includes the public //:trufflehog CLI, so default resolution cannot depend on a parent-repository label or binary declaration.
  • The existing native rule_test continues to supply its controlled scanner, exercising override precedence and executable runfiles independently of the default.
  • Default repository scans and standalone CLI builds must also resolve when the module alone registers all generated scanner toolchains and the root third-party package and platform-specific registration are absent.