Skip to content

ledgerprove/sign-sbom

LedgerProve — sign-sbom GitHub Action

GitHub Marketplace Release License

Cryptographically sign your SBOM, append it to a tamper-evident hash chain, and get a public verification URL — all in one CI step.

Quick start (auto-generates the SBOM for you)

- name: Sign SBOM with LedgerProve
  uses: ledgerprove/sign-sbom@v1
  with:
    api-key: ${{ secrets.LEDGERPROVE_API_KEY }}

That's the whole workflow step. The Action installs Syft, generates a CycloneDX SBOM of your repo, signs it with ECDSA-P521 (hardware-backed, non-exportable signing key), and prints a public verify URL.

Bring-your-own SBOM (full control)

If you already generate an SBOM in a previous step (cyclonedx-cli, custom tooling, etc.), pass it explicitly:

- name: Sign SBOM with LedgerProve
  uses: ledgerprove/sign-sbom@v1
  with:
    api-key: ${{ secrets.LEDGERPROVE_API_KEY }}
    sbom-file: ./my-sbom.json

What it does

  1. Reads your SBOM file (CycloneDX or SPDX, JSON).
  2. Hashes it with SHA-256.
  3. POSTs the hash + metadata to LedgerProve's API.
  4. The API signs your record with ECDSA-P521 using a private key inside a hardware-backed KMS — the key is non-exportable and never leaves the secure enclave.
  5. Your record is appended to a per-org SHA-512 hash chain — tampering with any record breaks all subsequent ones.
  6. An RFC 3161 timestamp is requested from a public TSA so anyone can prove when the record was signed.
  7. The Action sets verification-url as an output for use by later steps (PR comments, release notes, etc.).

Anyone can verify the signed SBOM at the verification URL with a single OpenSSL command. No account required.

Inputs

Input Required Default Description
api-key Your LedgerProve API key (lp_live_…). Generate at https://ledgerprove.com/dashboard. Store as a repo or org secret.
sbom-file Path to the SBOM JSON file. Generate it in an earlier step with syft, cyclonedx-cli, or your tool of choice.
repo-id ${{ github.repository }} Repository identifier under which to record this build.
commit-hash ${{ github.sha }} The commit SHA to record.
build-status PASS PASS, FAIL, or WARN. Use FAIL to record a failed build (e.g. tests failed, vulns found).
cve-count 0 Optional. CVE count to bake into the signed chain payload. Most users leave this at 0 — LedgerProve runs its own CVE scan against OSV.dev after every signed build and exposes the real findings on your dashboard. This field exists for callers who want to record a count from their own scanner inside the signature.
api-url https://api.ledgerprove.com Override the LedgerProve API URL. Only set this for self-hosted/staging.

Outputs

Output Description
verification-id Public verification ID (24-char hex)
verification-url Public URL anyone can use to verify the SBOM
signature-algorithm Always ECDSA-P521-SHA512
chain-index Position of this record in your organisation's chain
record-hash SHA-512 of the signed record
timestamped true if an RFC 3161 timestamp was attached

Full example — sign every build, post the verify URL on PRs

name: Build & Sign SBOM
on: [push, pull_request]

jobs:
  build-sign:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # 1. Generate an SBOM with Syft (works for any language / lockfile)
      - name: Generate SBOM
        uses: anchore/sbom-action@v0
        with:
          format: cyclonedx-json
          output-file: sbom.json

      # 2. Sign and chain it with LedgerProve
      - name: Sign with LedgerProve
        id: ledgerprove
        uses: ledgerprove/sign-sbom@v1
        with:
          api-key: ${{ secrets.LEDGERPROVE_API_KEY }}
          sbom-file: ./sbom.json

      # 3. Comment the verification URL on the PR
      - name: Comment verify URL on PR
        if: github.event_name == 'pull_request'
        uses: actions/github-script@v7
        with:
          script: |
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: '🛡 SBOM signed: ${{ steps.ledgerprove.outputs.verification-url }}'
            })

Setting up the API key

  1. Sign in at https://ledgerprove.com/login (GitHub or Google).
  2. Click Generate API key in your dashboard.
  3. Copy the lp_live_… value (shown once).
  4. In your GitHub repo (or org): Settings → Secrets and variables → Actions → New repository secret
    • Name: LEDGERPROVE_API_KEY
    • Value: paste your key
  5. Use ${{ secrets.LEDGERPROVE_API_KEY }} in your workflow.

Free plan limits

  • 1 repository with unlimited builds.
  • ECDSA-P521 signing on every build.
  • Public verification links forever.

For more repos, CVE alerts, SBOM diff and team accounts, see https://ledgerprove.com/pricing.

Verifying a signed SBOM yourself

Anyone can verify a record without a LedgerProve account:

# 1. Fetch the public record
curl -s https://api.ledgerprove.com/verify/<verification-id>

# 2. Download our public key
curl -sO https://api.ledgerprove.com/.well-known/public-key.pem

# 3. (Optional) Verify the RFC 3161 timestamp with OpenSSL
openssl ts -reply -in token.tsr -text

FAQ

How is this different from sigstore / cosign?

Sigstore uses keyless signing through a transparency log and a public Certificate Authority (Fulcio). It's a great fit if you want zero key management and are happy depending on a CA.

LedgerProve doesn't use a CA. Each organisation has a long-lived ECDSA-P521 key held inside a hardware-backed KMS, and records are appended to a per-org hash chain. The trade-off:

  • Sigstore wins if you want true keyless signing with a public transparency log
  • LedgerProve wins if you want signing without a CA dependency, with FIPS-aligned crypto, and a single-step CI integration

Both produce verifiable artifacts; the trust models differ.

Why ECDSA-P521 instead of Ed25519?

P521 is FIPS-186-5 approved (matters for some customers' compliance reviews) and AWS KMS supports it for signing today; Ed25519 in KMS is still not GA. We'd switch when Ed25519 lands.

Why a hash chain instead of a Merkle tree / transparency log?

A per-org hash chain is simpler operationally and gives the same tamper-evidence properties for a single organisation's history. A global Merkle log (like Rekor) gives cross-org public auditability — useful if you're publishing widely-consumed artifacts, less useful for internal SBOMs. We chose the simpler model for the MVP.

Does the action send my SBOM contents to your servers?

No. The action computes a SHA-256 of the SBOM locally and sends only the hash + metadata. The SBOM body never leaves your runner. The signed record references the hash, not the file. (Trade-off: you need to keep the SBOM retrievable yourself if you want full reproducibility later — sigstore goes the other way with attestation bundles.)

What happens if your service goes down?

Already-signed records remain verifiable forever using the public key at https://api.ledgerprove.com/.well-known/public-key.pem. If you cache the public key locally, you can verify signatures with OpenSSL even if our API is unreachable. New signings would obviously fail until we're back up.

Is there a free plan?

Yes — 1 repository, unlimited builds, no credit card. The open-source action and the public verify endpoint are free on every plan. See https://ledgerprove.com/pricing for paid tiers (more repos, longer history retention, SBOM diff, CVE email alerts).

Why is dist/ checked in?

GitHub Actions runs the compiled JavaScript directly — there's no install step at action runtime. The compiled output has to be in the repo. We rebuild dist/ on every change in src/.

License

MIT. Source: https://github.com/ledgerprove/sign-sbom

Security

For security disclosures, see SECURITY.md — do not report security issues via public GitHub Issues.

Contributing

PRs welcome. Read CONTRIBUTING.md first for scope and process.

Issues / questions

About

Cryptographically sign your SBOM with ECDSA-P521 + RFC 3161 timestamps. Tamper-evident, publicly verifiable. One GitHub Action step. EU CRA-ready.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors