Configuring guardrails
The guardrails section of buildnote.json lists the guardrails that buildnote guardrails runs. Each entry names a guardrail from the shared library and configures it for your project. The same block in a file of its own is a policy, which holds one part of a repository to account rather than all of it.
{
"guardrails": {
"failOn": "error",
"checks": [
{
"use": "git/conventional-commits@v1",
"severity": "error",
"with": {
"baseRef": "origin/main"
},
"exemptions": [
"^Revert "
]
}
]
}
}| Option | Type | Default | Description |
|---|---|---|---|
failOn | string | error | Severity that fails the build when a guardrail fails. One of error, warning, never. |
sources | array | [] | Libraries a reference resolves against after the one bundled with the CLI. |
checks | array | [] | The guardrails to run. |
A guardrail runs because it appears in checks. Delete the entry to stop running it, or narrow a single run with --only <id> without editing the file.
sources
The library bundled with the CLI is always the first place a reference resolves, and it is the only one you need for the guardrails Buildnote ships. sources adds your own libraries after it, in the order you list them: a reference that the bundled library does not declare is looked for in each of them in turn, and the first one that declares it wins.
{
"guardrails": {
"sources": [
"github://acme/our-guardrails",
"./guardrails"
],
"checks": [
{
"use": "team/no-todo-in-main@v1"
}
]
}
}| Form | Resolves to |
|---|---|
github://<owner>/<repository> | https://raw.githubusercontent.com/<owner>/<repository>/<version>/..., so the reference's version is the git ref and a tag is what pins it |
a path such as ./guardrails | that directory on the machine running the command, which is one version, so the version is checked against the definition's own version field |
A use reference can also name a repository inline as github://<owner>/<repository>/<category>/<name>@<version>. That reference resolves against that repository only, ignoring both the bundled library and sources. Its collectors are the exception: one that repository does not ship falls back to the library bundled with the CLI, so "collect": ["git"] works in a guardrail Buildnote never shipped.
A guardrail a source declares nothing for is a configuration error rather than a skip, so a mistyped id never passes quietly. A source that cannot be reached at all is missing evidence instead, and is recorded as skipped.
What a source runs on your machine
A guardrail resolved from a source of your own downloads a check script and its collectors' scripts and runs them on the machine running the command. The CLI prints the resolved location and the SHA-256 of every script it runs, for collectors as well as checks. sha256 on a check entry pins the check script only, not the collector scripts it reads its facts from, so pin the git ref rather than a branch in a github:// source you do not own.
checks
| Option | Type | Default | Description |
|---|---|---|---|
use | string | required | Guardrail reference, [github://<owner>/<repository>/]<category>/<name>@<version>, naming a guardrail of the library the CLI ships, of a sources entry, or of the repository it names itself. The version is required. See Writing a guardrail. |
severity | string | definition value | Overrides the definition's severity. One of error, warning, info. |
with | object | {} | Values for the guardrail's inputs, overriding the defaults in its definition. |
exemptions | array | [] | Regular expressions matched against a violation's evidence line. Matching violations are dropped before the verdict is decided. |
sha256 | string | none | Pins the check script's SHA-256. A mismatch skips the guardrail with a warning instead of running it. |
Each shipped guardrail's page carries a ready to paste example with that guardrail's own inputs. See the guardrails reference for the list.
Policies
A policy is the same guardrails block in a file of its own, named and pointed at the directories it holds to account. One repository carrying several modules gives each of them a policy rather than one buildnote.json everything shares.
{
"name": "checkout",
"moduleId": "checkout",
"paths": [
"services/checkout",
"services/checkout-worker"
],
"guardrails": {
"failOn": "error",
"checks": [
{
"use": "git/conventional-commits@v1"
}
]
},
"report": {
"github": {
"enabled": true
}
}
}buildnote guardrails --policy policies/checkout.json| Option | Type | Default | Description |
|---|---|---|---|
name | string | the file name without its extension | Names the policy in its pull request comment and in the report it writes. |
moduleId | string | the policy name | Module the events are submitted under, which is what keeps two policies in one build apart. |
paths | array | the directory the policy file is in | Directories the checks run in, relative to where the command is run. |
guardrails | object | none | The same block as in buildnote.json, replacing it for this run. |
report | object | the report of buildnote.json | The same block as in buildnote.json, replacing it for this run. |
--policy replaces the guardrails and the report of buildnote.json rather than adding to them, and --only, --fail-on and the --slack-*, --discord-*, --github-* and --html-* reporter options narrow or override the policy exactly as they do the file. Run one policy per command, and a job that runs several gets one pull request comment and one HTML report per policy, each named after it.
Every collector runs once per path, so a check sees the directory it is held to rather than the repository root, and a guardrail run over several paths reports one verdict carrying every path's violations, each prefixed with the path it was found in. A path that is not a directory is a configuration error: the command reports it and exits non zero.
Reporting without gating
Guardrails report their verdicts and never fail the build:
{
"guardrails": {
"failOn": "never",
"checks": [
{
"use": "git/conventional-commits@v1"
}
]
}
}