Skip to content
BETAGuardrails are in beta. The library, the configuration format and the CLI command can still change.

Guardrails

A guardrail is a reusable policy that runs in your pipeline and produces a verdict. You enable one by listing it in buildnote.json and running buildnote guardrails. The CLI fetches the guardrail, runs its check on the runner, records the verdict in Buildnote as a guardrail event, comments the result on the pull request, and optionally fails the build.

Guardrails cover the rules a team agrees on but has no good place to enforce: commit message format, no merge commits, a dependency policy, a coverage floor. You configure them rather than write them, and every run is recorded, so you can see how a rule trends across builds instead of only whether today's build passed.

Browse the library

Buildnote ships 110 guardrails. Filter them by name, by what they check, by category or by severity, and open one for its inputs, its configuration example and how to fix what it finds.

110 guardrails. Showing the first 40.

build4

clojure4

cpp4

docs7

dotnet4

elixir3

git6

golang4

iac4

Categories

Each category is one directory of the library, sharing a version and the inputs its guardrails have in common. Its page lists every guardrail in it and the inputs they share.

CategoryGuardrails
build4
clojure4
cpp4
docs7
dotnet4
elixir3
git6
golang4
iac11
java3
kotlin4
maven4
nodejs4
ownership6
php3
pipeline5
python4
ruby4
rust4
scala4
secrets4
security4
supply-chain6
tests4

To write your own, read Writing a guardrail. A guardrail rarely gathers its own evidence: it declares a collector, which gathers the repository, the build and the files once per run and hands the same document to every guardrail that asked.

Configuration

Every option is described in Configuring guardrails.

Running

bash
buildnote guardrails --org acme --project web --module ci --build 1234

In a CI environment that Buildnote recognises, the organisation, project, module, build, commit and ref are all detected for you, so the command is usually just:

bash
buildnote guardrails

Use --only <id> to run a single guardrail, --dry-run to print the verdicts without recording or reporting anything, and --fail-on never to report without gating. See the command reference for every option.

Verdicts

A guardrail run ends in one of three verdicts.

VerdictMeaningEvent status
passedThe check ran and found nothing over the guardrail's threshold.successful
failedThe check ran and found more violations than the guardrail tolerates.failed
skippedThe check could not gather its evidence, so it has no opinion.skipped

Skipping is a first class outcome. A guardrail that cannot see what it needs never fails your build. The CLI decides skipped when:

  • the check reports it cannot run, such as a base ref that does not resolve on a shallow clone
  • the check produces no readable result
  • the interpreter is missing on the runner, or the check runs past its timeout
  • the guardrail's source cannot be reached, so its definition or script could not be read
  • the pinned sha256 does not match the script that was fetched, which prints a warning rather than passing quietly

After a check runs, the exemptions of your check entry are applied to the violations it reported, and what remains is compared against the guardrail's maxViolations. That comparison decides failed or passed.

Failing the build

failOn decides which verdicts gate the build.

ValueThe build fails when
error (default)a guardrail with severity error fails
warninga guardrail with severity error or warning fails
nevernever

The command always records the verdicts and posts the pull request comment before it exits, so a gated build still reports everything it found. A guardrail whose events cannot be submitted still gates.

A guardrail that cannot be loaded at all is a different thing from a verdict, and failOn does not cover it. A definition that is malformed, declares a version your check entry does not expect, or names a script whose extension selects no interpreter is a configuration error: the command reports it, runs every other guardrail, and then exits non zero whatever failOn says. A source that simply cannot be reached is treated as missing evidence instead, so it is recorded as skipped.

Reporting

Guardrails report through the same reporters as buildnote report, configured in the same report section of buildnote.json. Every one of them receives the same verdict table, most severe first, with the evidence and remediation for each failed guardrail.

ReporterWhat it does
githubWrites the markdown to the job summary, and posts it on the pull request as a comment titled Guardrails. A re-run updates that comment rather than adding another, and it never collides with the test summary comment.
htmlWrites a standalone Guardrails document. With no outputFile it is buildnote-guardrails.html; with one it is written beside it as a -guardrails sibling, so build/report.html gives build/report-guardrails.html and your test report is not overwritten.
slackPosts a notification with a line and a status icon per guardrail.
discordThe same notification, as a Discord message.

A reporter runs when it is enabled and its condition passes, exactly as for buildnote report. A condition is evaluated against the guardrail run rather than the test run, so the same expressions mean the guardrail equivalent:

VariableMeaning
successful failed skippedBooleans for the run's overall verdict.
successful.count failed.count skipped.countHow many guardrails reached each verdict.
totalHow many guardrails ran.
violationsViolations across the whole run.
statussuccessful, failed, skipped or unknown.
always nevertrue and false.
org project module build sha refThe build coordinates.

An expression that cannot be resolved degrades to empty rather than aborting the run, and a reporter that cannot be resolved at all is reported and skipped. Neither changes the exit code.

The pull request comment needs a GitHub token, which comes from report.github.token or the --github-token option. Without a token, without a pull request, or with "comment": false, the command skips the comment and carries on. No reporter failure changes the exit code: the verdict decides that, not whether somebody could be told about it.

Querying verdicts

Every run is recorded as two kinds of guardrail event, queryable through the guardrails table. One run event summarises the whole invocation, carrying the total violation count and, as attachments, the facts every collector gathered. One check event per guardrail carries its own verdict and relates back to the run:

sql
SELECT guardrail, status, violations FROM guardrails WHERE build = '1234' AND category = 'check'
sql
SELECT guardrail, COUNT(*) AS failures FROM guardrails WHERE status = 'failed' AND category = 'check' GROUP BY guardrail ORDER BY failures DESC

Re-running a guardrail in the same build replaces its earlier verdict, so a build holds one row per guardrail. The entity_id is stable across builds, so you can trend one guardrail over time.

Buildnote Limited
Registered in England and Wales, Reg: 16140412