operations

Finding baselines

Keep accepted package findings visible without failing audits.

Last updated July 27, 2026View source (v0.20.2)

Finding baselines let a project keep known package findings visible without letting those findings fail an audit. Bomly automatically looks for .bomly/baseline.json when scan, diff, or explain runs against a project. A matching finding is still emitted with the same package, advisory, severity, and reasons, but its policy status becomes suppressed. Machine-readable findings expose the status as policy_status.

Create and maintain a baseline

Baseline creation runs the normal audited project pipeline and therefore requires explicit enrichment:

bomly baseline create --enrich
bomly baseline inspect
bomly baseline inspect --path ../another-project

Creation refuses to overwrite an existing file. baseline update --enrich accepts current new or changed findings while retaining historical entries. baseline prune --enrich removes accepted entries absent from a complete current audit and never accepts new findings. All writes use a temporary file and atomic replacement. Lifecycle commands are limited to writable local filesystem projects and refuse to mutate a baseline when the scan reports degraded detector, matcher, analyzer, or auditor coverage. Use --analyze for lifecycle commands when the audited CI workflow also uses reachability analysis. The baseline records that policy state as a safety bound.

Selection

The shared --baseline option accepts:

  • auto (default): use .bomly/baseline.json when present;
  • none: disable baseline consumption;
  • a relative or absolute path: require that baseline file.

A relative path is resolved from the project root. During a Git diff it is resolved independently in the materialized base and head trees, so each side uses the baseline committed with that project state. The merge base selected by Bomly Guard is simply the diff's base tree.

Automatic discovery also applies to --url targets, using the baseline committed in the checked-out repository. Use --baseline none when that project policy should not participate in evaluation, or provide an explicit path to use a different baseline. At -v, Bomly logs every detected baseline with its path, entry count, selection mode, and target kind. Audit completion logs include the baseline path, entries, findings evaluated, and findings accepted, including when those counts are zero.

If automatic discovery sees a symbolic-link .bomly directory or baseline.json, Bomly warns and behaves as though no project baseline exists. This rejects links discovered during path inspection; it does not protect against another process replacing a path between inspection and reading. An explicit --baseline <path> is different: it is a trusted path selected by the user and may refer to a symbolic link or a file outside the project.

Container targets have no reliable project root, so they require an absolute baseline path. For a standalone SBOM file, automatic discovery starts beside the file; an explicit path is recommended when the baseline lives elsewhere.

policy:
  baseline: auto

Identity and portability

Entries identify the full package PURL (including version), finding kind, auditor, and either advisory identifiers or a stable policy rule. They do not contain dependency node IDs, manifest paths, subproject names, project names, or mutable finding prose.

A baseline can therefore be copied to another project and suppresses the same finding for the same package version there. It does not automatically suppress the finding after a package version changes. Advisory aliases are retained so equivalent identifiers can match across enrichment sources.

{
  "schema_version": "bomly.finding-baseline/v1",
  "entries": [
    {
      "package_ref": "pkg:npm/example@1.0.0",
      "kind": "package",
      "auditor": "package",
      "rule_id": "denied-package",
      "severity": "high",
      "policy_status": "fail"
    }
  ]
}

Structured findings expose rule_id, so a non-vulnerability entry can be reviewed or authored without relying on mutable finding titles.

Severity, failing policy status, and reachability state are recorded as safety bounds. An escalation remains unsuppressed until baseline update explicitly accepts it. A safer reachability result remains accepted: for example, a finding recorded as unknown stays suppressed if analysis later proves it unreachable, but becomes gating if analysis reports it reachable.

Output and automation

Baselines do not add report sections or collections. Findings remain in their normal scan, explain, and diff locations. JSON and MCP expose the policy_status field; text, Markdown, and the TUI call it the policy status; SARIF marks the result as externally suppressed at note level; and Bomly Guard continues consuming the ordinary diff output and exit status. The CLI output schema identifier remains 1.0.

Baseline failures do not hide pipeline diagnostics. A malformed explicitly selected file fails before the audit runs. An automatically discovered baseline is loaded only for audited commands, so a malformed file cannot break a plain inventory scan; audited commands fail closed rather than silently ignoring it. Bomly rejects baseline files larger than 16 MiB and baseline documents with more than 10,000 entries.