Skip to content

Guardrails / Collectors

Secrets in the checkout ​

Secrets found in the checkout, read from the report a secret scanner already left behind, or collected by running gitleaks or trufflehog when the runner carries one and no report is there. Only the rule, the file, the line and a fingerprint are collected: the matched value never is, because these facts are attached to the run event.

Facts keysecrets
Versionv1
Scriptsecrets.py
Timeout300 seconds

Tools ​

This collector reads what these tools report, but it never installs them. If a tool isn't on the runner, the evidence is missing and the guardrails that need these facts skip instead of failing.

ToolNeededDescription
gitleaksoptionalSecret detector, run over the checkout when no report is there. Preferred over trufflehog because it reports SARIF.
trufflehogoptionalSecret detector that verifies what it finds against the service it belongs to, run when gitleaks is not there.

Installing gitleaks ​

Install gitleaks with brew install gitleaks, or docker run --rm -v $(pwd):/repo zricethezav/gitleaks:latest detect --source /repo, or run the gitleaks/gitleaks-action@v2 step before this one and leave its report in the checkout.

Installing trufflehog ​

Install trufflehog with brew install trufflehog, or curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh | sh -s -- -b /usr/local/bin, or run the trufflesecurity/trufflehog@main step before this one.

Inputs ​

InputDescriptionDefaultEnvironment
reportsComma separated globs matched against every file in the working directory and against bare file names, naming the secret scanner reports to read. Narrow it when several reports are present and only one of them should decide.gitleaks*.sarif,gitleaks*.json,trufflehog*.json,.secrets.baselineGUARDRAIL_INPUT_REPORTS
scanHistoryWhether a tool the collector runs scans the repository's git history instead of the working tree. Scanning the history finds a secret that was committed and later removed, at the cost of reading the whole log. Ignored when a report was found, because the report is what the pipeline already acted on.falseGUARDRAIL_INPUT_SCANHISTORY
maxFindingsMaximum number of findings to carry in the facts. The counts still include findings that are dropped.200GUARDRAIL_INPUT_MAXFINDINGS

When a guardrail declares an input with the same name, it passes its value through. That means you set these values in the guardrail's configuration in buildnote.json.

A guardrail asks for these facts by name and reads them back by the same name:

json
{
  "collect": ["secrets"]
}
python
secrets = guardrail.facts("secrets")

Facts ​

These are the fields of the document secrets collects. In a path, [] means each entry of the list before it, and [path] means a key of the object before it.

FactMeaning
sourcereport when a secret scanner's report was read, tool when the collector ran one itself, none when there was neither.
reasonWhy nothing was collected, present only when source is none. It names the globs that matched no readable report and the tool to install.
reportsEvery report that was read, in path order.
reports[].pathPath of the report, relative to the directory the CLI runs in.
reports[].modifiedWhen the report was last written, in ISO 8601, so you can spot a stale report.
reports[].formatFormat it was read as: sarif, gitleaks, trufflehog or detect-secrets.
tool.nameTool that was run, present only when no report was found and one was on the PATH.
tool.versionVersion that tool reported when the CLI probed it, so you know which scanner decided this build was clean.
tool.pathWhere on the PATH it was resolved to.
tool.argsArguments it was run with, so the same scan runs by hand.
tool.exitCodeCode it exited with. A secret detector exits non zero when it finds something, so this is a result rather than a failure.
tool.durationMsHow long the invocation took.
counts.totalSecrets found, across every report that was read or everything the tool printed.
counts.bySeverity.criticalFindings the scanner verified against the service the credential belongs to, so it is known to be live.
counts.bySeverity.highFindings reported without being verified, which is the usual case for a secret detection.
counts.bySeverity.mediumFindings the report rated medium.
counts.bySeverity.lowFindings the report rated low.
counts.bySeverity.infoFindings the report rated informational.
counts.bySeverity.unknownFindings the report gave no severity, or a severity that is not recognised.
findingsThe findings themselves, up to maxFindings.
findings[].idRule the scanner matched, such as aws-access-token, or the detector that matched it.
findings[].severitycritical, high, medium, low, info or unknown.
findings[].messageWhat the scanner said about the rule, truncated to 500 characters. Never the value it matched.
findings[].pathFile the secret was found in, relative to the working directory, or null.
findings[].lineLine it was found on, or null.
findings[].fingerprintStable identity of the finding across runs, derived from the rule, the file and the line, so the same secret is recognisable in a later build without carrying it.
droppedFindings left out because maxFindings was reached.

If a collector can't finish, it prints what it gathered so far along with an incomplete key that says why. Facts after the point where it stopped are missing, so a check that depends on them should read incomplete first.

Example facts ​

Here are the facts the secrets collector gathers from an example project:

json
{
  "source": "report",
  "reports": [
    {
      "path": "gitleaks.sarif",
      "modified": "2026-03-04T10:15:00Z",
      "format": "sarif"
    }
  ],
  "counts": {
    "total": 1,
    "bySeverity": {
      "critical": 0,
      "high": 1,
      "medium": 0,
      "low": 0,
      "info": 0,
      "unknown": 0
    }
  },
  "findings": [
    {
      "id": "aws-access-token",
      "severity": "high",
      "message": "aws-access-token has detected a secret in service/src/main/resources/application.yaml.",
      "path": "service/src/main/resources/application.yaml",
      "line": 14,
      "fingerprint": "19d0004f552705be"
    }
  ],
  "dropped": 0
}

Collected for ​

GuardrailCategoryInputs
secrets/detector-ransecretsnone
secrets/no-hardcoded-credentialssecretsnone

All collectors

Buildnote Limited
Registered in England and Wales, Reg: 16140412