Hamburger Cross Icon
SBOM Guardrails - Lunar Policy for Security And Compliance

SBOM Guardrails

✓ Policy Stable Security And Compliance

Enforce Software Bill of Materials standards across your organization. Verify SBOMs are generated, contain license data, use approved formats, keep licenses within an allow-list or out of a denylist, and flag dependencies with blocked geographic origins or disallowed package patterns.

Add sbom to your lunar-config.yml:
uses: github://earthly/lunar-lib/policies/sbom@v1.0.5

Included Guardrails

This policy includes 8 guardrails that enforce standards for your security and compliance.

Guardrail

sbom-exists

Ensures an SBOM was generated, either automatically or detected in CI.

sbom software bill of materials compliance
View Guardrail
Guardrail

has-licenses

Verifies that SBOM components have license information populated. Fails if license coverage is below the configured threshold.

sbom licenses license coverage
View Guardrail
Guardrail

disallowed-licenses

Checks for disallowed licenses in SBOM components. Matches component licenses against configurable regex patterns.

sbom licenses compliance gpl copyleft
View Guardrail
Guardrail

allowed-licenses

Fails when an SBOM component carries a license that allowed_licenses does not admit. Skips until allowed_licenses is configured.

sbom licenses license allow-list approved licenses compliance
View Guardrail
Guardrail

min-components

Verifies the SBOM contains a minimum number of components. Catches trivially empty SBOMs that may indicate detection failures.

sbom completeness components
View Guardrail
Guardrail

standard-format

Validates the SBOM uses an approved format (CycloneDX, SPDX). Auto-passes if no format restriction is configured.

sbom cyclonedx spdx format
View Guardrail
Guardrail

blocked-origins

Checks for dependencies with license origin mentions from blocked countries. Supports blocklist or allowlist mode. Requires the license-origins collector.

sbom license origins country of origin export control compliance supply chain
View Guardrail
Guardrail

disallowed-packages

Checks for disallowed packages by matching PURL, name, or group against configurable regex patterns (e.g. "ru\.yandex\..", "com\.alibaba\..").

sbom disallowed packages package blocklist supply chain compliance
View Guardrail

How Guardrails Fit into Lunar

Lunar guardrails define your engineering standards as code. They evaluate data collected by integrations and produce pass/fail checks with actionable feedback.

Policies support gradual enforcement—from silent scoring to blocking PRs or deployments—letting you roll out standards at your own pace without disrupting existing workflows.

Learn How Lunar Works →
1
↓ Integrations Gather Data
Collectors extract metadata from code, CI pipelines, tool outputs, and scans
2
{ } Centralized as JSON
All data merged into each component's unified metadata document
3
✓ Guardrails Enforce Standards This Policy
Real-time feedback in PRs and AI workflows

Required Integrations

This policy evaluates data gathered by one or more of the following integration(s). Make sure to enable them in your lunar-config.yml.

Configuration

Configure this policy in your lunar-config.yml.

Inputs

Input Required Default Description
disallowed_licenses Required — Regex patterns of disallowed licenses. Accepts a comma-separated string (e.g. "GPL.*,AGPL.*") or a JSON array (e.g. '["GPL.*", "AGPL.*"]').
allowed_licenses Required — Licenses components may use, as SPDX IDs or regex patterns that must match the whole ID, case-insensitively (e.g. '["MIT", "Apache-2.0", "BSD-.*-Clause"]'). Accepts a comma-separated string or a JSON array. Empty skips the allowed-licenses check.
min_license_coverage Optional 50 Minimum percentage of components that must have license info (0-100)
min_components Optional 1 Minimum number of components the SBOM must contain
allowed_formats Required — Comma-separated list of allowed SBOM formats (e.g. "cyclonedx,spdx"). Empty means any.
blocked_countries Required — Comma-separated list of blocked countries for license origin checks (e.g. "Russia,China,Iran,North Korea")
disallowed_packages Required — Regex patterns for disallowed packages, matched against PURL, name, and group. Accepts a comma-separated string or a JSON array (e.g. '["ru\\.yandex\\..*", "com\\.alibaba\\..*"]').

Documentation

View on GitHub

SBOM Guardrails

Enforces SBOM existence, license compliance, completeness, and format standards.

Overview

This policy enforces Software Bill of Materials standards across your organization. It verifies that SBOMs are generated, contain license data, use approved formats, and keep licenses within an allow-list or out of a denylist. It works with data from both auto-generated SBOMs (via the syft collector) and CI-detected SBOMs, enabling vendor-agnostic SBOM governance.

Policies

This policy provides the following guardrails (use include to select a subset):

Policy Description Failure Meaning
sbom-exists Checks that an SBOM was generated No SBOM found from any source
has-licenses Verifies components have license info License coverage below threshold
disallowed-licenses Checks for disallowed license patterns Component uses a disallowed license
allowed-licenses Checks component licenses against an allow-list Component uses a license the allow-list does not admit
min-components Verifies minimum component count SBOM has too few components
standard-format Validates SBOM format SBOM uses a non-approved format
blocked-origins Checks for license origin mentions from blocked countries Dependency has country mention from blocklist
disallowed-packages Checks for disallowed packages by PURL/name/group pattern Package matches a disallowed pattern

How allowed-licenses evaluates licenses

  • Every license a component carries is checked: CycloneDX license.id, license.name and expression, and SPDX licenseConcluded (falling back to licenseDeclared). A component that lists several licenses needs each of them allowed.
  • SPDX expressions: A OR B passes if either side is allowed and A AND B needs both. X WITH exception passes if you list the full pair, or if X is allowed and the exception is on the SPDX exceptions list, whose entries only relax a license. So Apache-2.0 admits Apache-2.0 WITH LLVM-exception but not Apache-2.0 WITH Commons-Clause. X+ passes if X is allowed.
  • Entries match the whole license ID, case-insensitively, as written or as a regex: MIT admits MIT but not MIT-0, and BSD-.*-Clause admits the BSD clause family. This differs from disallowed_licenses, which matches anywhere in the ID. A listed X WITH exception pair, and a multi-word name that isn't an SPDX expression such as MIT License or MIT with modifications (operators must be uppercase), match only as written, so a pattern can't stretch across them.
  • An SPDX LicenseRef-… is also admitted by the name it resolves to, so Commercial covers syft's CycloneDX Commercial and SPDX LicenseRef-Commercial alike.
  • Components with no license data, including SPDX NOASSERTION and NONE, are left to has-licenses rather than failed twice.

Required Data

This policy reads from the following Component JSON paths:

Path Type Provided By
.sbom.auto object syft collector (generate sub-collector)
.sbom.cicd object syft collector (ci sub-collector)
.sbom.auto.cyclonedx.components array syft collector
.sbom.cicd.cyclonedx.components array syft collector
.sbom.cicd.spdx.packages array syft collector (for allowed-licenses)
.sbom.license_origins.packages array license-origins collector (for blocked-origins check)

Note: Ensure the syft collector is configured before enabling this policy. The blocked-origins check additionally requires the license-origins collector.

Installation

Add to your lunar-config.yml:

policies:
  - uses: github://earthly/lunar-lib/policies/sbom@main
    on: ["domain:engineering"]
    enforcement: block-pr
    # include: [sbom-exists, disallowed-licenses]
    with:
      disallowed_licenses: "GPL.*,BSL.*,AGPL.*"
      # allowed_licenses: '["MIT", "Apache-2.0", "BSD-2-Clause", "BSD-3-Clause", "ISC"]'
      min_license_coverage: "90"
      min_components: "1"
      # allowed_formats: "cyclonedx"
      # disallowed_packages: '["alibabacloud", "aliyun-.*", ".*\\.ru$"]'

Tip: disallowed_licenses, allowed_licenses and disallowed_packages accept either a comma-separated string ("GPL.*,AGPL.*") or a JSON array string ('["GPL.*", "AGPL.*"]'). JSON arrays are recommended when patterns contain commas or complex regex.

Examples

Passing Example

All components have approved licenses and license coverage meets the threshold:

{
  "sbom": {
    "auto": {
      "source": { "tool": "syft", "integration": "code", "version": "1.19.0" },
      "cyclonedx": {
        "bomFormat": "CycloneDX",
        "specVersion": "1.5",
        "components": [
          {
            "name": "github.com/sirupsen/logrus",
            "version": "v1.9.3",
            "licenses": [{ "license": { "id": "MIT" } }]
          }
        ]
      }
    }
  }
}

Failing Example

A component uses a disallowed GPL license:

{
  "sbom": {
    "auto": {
      "cyclonedx": {
        "components": [
          {
            "name": "copyleft-lib",
            "licenses": [{ "license": { "id": "GPL-3.0" } }]
          }
        ]
      }
    }
  }
}

Failure message: "Component 'copyleft-lib' uses disallowed license 'GPL-3.0' (matches pattern 'GPL.*')"

Failing Example (allowed-licenses)

With allowed_licenses: '["MIT", "Apache-2.0"]', jszip passes because MIT is one of its alternatives, while pako needs Zlib as well:

{
  "sbom": {
    "auto": {
      "cyclonedx": {
        "components": [
          { "name": "jszip", "version": "3.10.1", "licenses": [{ "expression": "MIT OR GPL-3.0-or-later" }] },
          { "name": "pako", "version": "1.0.11", "licenses": [{ "expression": "MIT AND Zlib" }] }
        ]
      }
    }
  }
}

Failure message: "License 'MIT AND Zlib' is not in allowed_licenses: pako@1.0.11"

Remediation

When this policy fails, you can resolve it by:

  1. sbom-exists failure: Enable the syft collector or run Syft in your CI pipeline to generate an SBOM
  2. has-licenses failure: Ensure Syft has network access for remote license lookups, or add license metadata to your project dependencies
  3. disallowed-licenses failure: Replace the disallowed dependency with an alternative that uses an approved license, or update the disallowed_licenses input
  4. allowed-licenses failure: Replace the dependency, or add its license to allowed_licenses once it has been approved
  5. min-components failure: Verify Syft can detect your project's package manager and dependencies are declared correctly
  6. standard-format failure: Configure Syft to output in an approved format (e.g., cyclonedx-json) or update the allowed_formats input
  7. blocked-origins failure: Review the flagged package's license file to confirm the country mention is genuine (not a false positive), then either replace the dependency or update the blocked_countries/allowed_countries inputs
  8. disallowed-packages failure: Replace the disallowed dependency or update the disallowed_packages regex patterns

Open Source

This policy is open source and available on GitHub. Contribute improvements, report issues, or fork it for your own use.

View Repository

Common Use Cases

Explore how individual guardrails work with specific integrations.

+
Sbom Exists + Syft SBOM Collector Ensures an SBOM was generated, either automatically or detected in CI.
→
+
Sbom Exists + License Origins Collector Ensures an SBOM was generated, either automatically or detected in CI.
→
+
Has Licenses + Syft SBOM Collector Verifies that SBOM components have license information populated. Fails if...
→
+
Has Licenses + License Origins Collector Verifies that SBOM components have license information populated. Fails if...
→
+
Disallowed Licenses + Syft SBOM Collector Checks for disallowed licenses in SBOM components. Matches component licenses...
→
+
Disallowed Licenses + License Origins Collector Checks for disallowed licenses in SBOM components. Matches component licenses...
→
+
Allowed Licenses + Syft SBOM Collector Fails when an SBOM component carries a license that allowed_licenses does not...
→
+
Allowed Licenses + License Origins Collector Fails when an SBOM component carries a license that allowed_licenses does not...
→
+
Min Components + Syft SBOM Collector Verifies the SBOM contains a minimum number of components. Catches trivially...
→
+
Min Components + License Origins Collector Verifies the SBOM contains a minimum number of components. Catches trivially...
→
+
Standard Format + Syft SBOM Collector Validates the SBOM uses an approved format (CycloneDX, SPDX). Auto-passes if no...
→
+
Standard Format + License Origins Collector Validates the SBOM uses an approved format (CycloneDX, SPDX). Auto-passes if no...
→
+
Blocked Origins + Syft SBOM Collector Checks for dependencies with license origin mentions from blocked countries....
→
+
Blocked Origins + License Origins Collector Checks for dependencies with license origin mentions from blocked countries....
→
+
Disallowed Packages + Syft SBOM Collector Checks for disallowed packages by matching PURL, name, or group against...
→
+
Disallowed Packages + License Origins Collector Checks for disallowed packages by matching PURL, name, or group against...
→

Ready to Automate Your Standards?

See how Lunar can turn your AGENTS.md, engineering wiki, compliance docs, or postmortem action items into automated guardrails with our 200+ built-in guardrails.

Works with any process
check AI agent rules & prompt files
check Post-mortem action items
check Security & compliance policies
check Testing & quality requirements
Auto-ID My Guardrails
Paste your AGENTS.md or manual process doc and get guardrails in minutes
Book a Demo