@cognoshift/sanad-sbom
v0.1.0
Published
Sanad Sign CLI — generate, sign, and verify CycloneDX SBOMs against India's sovereign attestation rail.
Maintainers
Readme
sanad-sbom
Sanad Sign CLI — generate, sign, and verify CycloneDX SBOMs against India's sovereign attestation rail.
Zero dependencies. Node 18+. Works against any Sanad Sign-compatible endpoint (defaults to https://sanad.cognoshift.in).
Install
npm install -g @cognoshift/sanad-sbomOr run directly without installing:
npx @cognoshift/sanad-sbom push --source sentinel_inventory --subject my-appAuthenticate
Set your tenant license key either as a flag or an environment variable:
export SANAD_LICENSE_KEY="CS-CIV-..." # recommended for CI/CDCommands
push — generate + sign in one step (most common)
All sources flow through push the same way. The --source flag picks the input.
Fleet inventory — Sanad Sentinel-managed endpoints (server-side, needs tenant key):
sanad-sbom push --source sentinel_inventory --subject "my-fleet-$(date +%F)"Container image — Docker / OCI, via local Syft:
sanad-sbom push --source container --image docker:my-app:v1.2.3 --public
# One-time Syft install:
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/binnpm — parses package-lock.json (v1/v2/v3). Zero extra deps.
sanad-sbom push --source npm --public
# Or point at a specific lockfile:
sanad-sbom push --source npm --manifest /path/to/package-lock.jsonpip — parses requirements.txt (or pip freeze > reqs.txt):
sanad-sbom push --source pip --public
sanad-sbom push --source pip --manifest requirements-prod.txtmaven — parses pom.xml <dependencies> (direct deps only; test-scope skipped):
sanad-sbom push --source maven --public
# For full transitive graph, run Syft on target/:
syft dir:./target -o cyclonedx-json | sanad-sbom sign --sbom - --subject "my-app@$(git rev-parse --short HEAD)"nuget — parses packages.lock.json (enable via msbuild /t:restore /p:RestorePackagesWithLockFile=true):
sanad-sbom push --source nuget --publicAll sources emit CycloneDX 1.6, sign with Ed25519, and register in the Sanad ledger. Subject defaults to the project coordinates (name@version from the manifest) if not supplied.
generate — produce an SBOM without signing
sanad-sbom generate --source sentinel_inventory --output sbom.jsonsign — sign an existing SBOM JSON file
sanad-sbom sign --sbom sbom.json --subject my-app --public--public makes the signed attestation world-readable on the registry.
verify — confirm a signed attestation
Online (looks up the attestation + replays the hash chain):
sanad-sbom verify --id <attestation-uuid>Offline (pure cryptography, no network):
sanad-sbom verify \
--sbom sbom.json \
--signature "<base64>" \
--public-key "<base64>"Flags
| Flag | Description |
|---|---|
| --license-key <KEY> | Tenant license key. Or use SANAD_LICENSE_KEY env. |
| --endpoint <URL> | Override the default endpoint. Or use SANAD_ENDPOINT env. |
| --json | Machine-readable JSON output (good for CI pipelines). |
GitHub Actions
- name: Sign SBOM
run: |
npm install -g @cognoshift/sanad-sbom
sanad-sbom push --source sentinel_inventory --subject "${{ github.repository }}@${{ github.sha }}"
env:
SANAD_LICENSE_KEY: ${{ secrets.SANAD_LICENSE_KEY }}How verification works
Sanad Sign signatures are Ed25519 over the SHA-256 hash of the canonical (sorted-key) CycloneDX serialization. The public key is frozen on every attestation row at signing time, so any verifier — including auditors without access to Sanad — can verify offline using crypto.verify() in 10 lines of code in any language.
Chain integrity: every attestation is appended to a per-tenant SHA-256 hash chain anchored to the genesis constant SANAD_SIGN_GENESIS_2026. The verify --id command replays the entire chain from genesis and flags any tampering.
License
Apache-2.0
