Cryptographically sign your SBOM, append it to a tamper-evident hash chain, and get a public verification URL — all in one CI step.
- 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.
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- Reads your SBOM file (CycloneDX or SPDX, JSON).
- Hashes it with SHA-256.
- POSTs the hash + metadata to LedgerProve's API.
- 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.
- Your record is appended to a per-org SHA-512 hash chain — tampering with any record breaks all subsequent ones.
- An RFC 3161 timestamp is requested from a public TSA so anyone can prove when the record was signed.
- The Action sets
verification-urlas 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.
| 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. |
| 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 |
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 }}'
})- Sign in at https://ledgerprove.com/login (GitHub or Google).
- Click Generate API key in your dashboard.
- Copy the
lp_live_…value (shown once). - In your GitHub repo (or org): Settings → Secrets and variables → Actions → New repository secret
- Name:
LEDGERPROVE_API_KEY - Value: paste your key
- Name:
- Use
${{ secrets.LEDGERPROVE_API_KEY }}in your workflow.
- 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.
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 -textSigstore 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.
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.
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.
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.)
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.
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).
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/.
MIT. Source: https://github.com/ledgerprove/sign-sbom
For security disclosures, see SECURITY.md — do not report security issues via public GitHub Issues.
PRs welcome. Read CONTRIBUTING.md first for scope and process.
- General: https://github.com/ledgerprove/sign-sbom/issues
- Discussions: https://github.com/ledgerprove/sign-sbom/discussions
- Email: hello@ledgerprove.com