ledgerprove/sign-sbom
GitHub: ledgerprove/sign-sbom
Stars: 0 | Forks: 0
# LedgerProve — sign-sbom GitHub Action
[](https://github.com/marketplace/actions/ledgerprove-sign-sbom)
[](https://github.com/ledgerprove/sign-sbom/releases)
[](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
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/
# 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](LICENSE). Source: https://github.com/ledgerprove/sign-sbom
## Security
For security disclosures, see [SECURITY.md](SECURITY.md) — do not report security issues via public GitHub Issues.
## Issues / questions
- General: https://github.com/ledgerprove/sign-sbom/issues
- Discussions: https://github.com/ledgerprove/sign-sbom/discussions
- Email: hello@ledgerprove.com
标签:自动化攻击