Verify what AGLedger ships
AGLedger ships four artifact surfaces: the Server container image, the Helm chart, the npm packages, and the PyPI package. Every one is built and signed by CI under a single keyless trust root: GitHub Actions OIDC to Sigstore (Fulcio) to the public Rekor transparency log. There is no long-lived signing token or static key for any published artifact, and verification runs entirely against the public Sigstore trust root, with no AGLedger-hosted key, endpoint, or source-repository access.
This page is the single index for the verify recipes. The image and chart recipes are
also maintained in the install repository's SECURITY.md,
which agrees with this page on the trust root. The npm and PyPI recipes below are the
canonical copy.
Assurance level, per artifact
The SLSA Build level is stated per artifact rather than flattened to one number. The container and registry paths earn different guarantees, and over-claiming on either is exactly what a security reviewer flags.
| Artifact | Provenance mechanism | SLSA Build level |
|---|---|---|
Server image agledger/agledger | cosign keyless + slsa-github-generator isolated builder, plus SBOM, OpenVEX and malware-scan attestations | L3 |
Helm chart agledger/agledger-chart | cosign keyless signature only | none of its own |
npm packages @agledger/{verify-core,verify,sdk,cli,mcp-server} | npm provenance attestation (Sigstore) + signed CycloneDX SBOM attestation | L2 |
PyPI package agledger | PEP 740 attestation via PyPI Trusted Publishing | signed publish attestation, no numbered level |
The image reaches SLSA Build L3 because its provenance is produced by an isolated reusable workflow the build steps cannot tamper with. The chart carries a signature and no provenance or SBOM of its own: it is a templates tarball, and every attestation lives on the image digest it deploys. The npm packages publish hosted build provenance via Trusted Publishing, OIDC-bound and non-forgeable but without the isolated-builder guarantee, which is SLSA Build L2. PyPI's PEP 740 attestations bind each file to its publishing workflow and are not mapped to a numbered SLSA level.
Server image and Helm chart
Both are keyless-signed with cosign. A valid signature binds to the GitHub Actions workflow that built the release. Requires cosign 3.0 or later. Set the release you are verifying once:
VERSION=2.0.0
IDENTITY='^https://github\.com/agledger-ai/agledger-api/\.github/workflows/.+@refs/tags/v.+$'
ISSUER='https://token.actions.githubusercontent.com'
Verify the image signature, then the chart:
$ cosign verify --certificate-identity-regexp "$IDENTITY" --certificate-oidc-issuer "$ISSUER" \
agledger/agledger:$VERSION
$ cosign verify --certificate-identity-regexp "$IDENTITY" --certificate-oidc-issuer "$ISSUER" \
registry-1.docker.io/agledger/agledger-chart:$VERSION
Each prints Verification for ... and a JSON block whose certificate identity is the
GitHub Actions workflow that built the artifact. Verify the CycloneDX SBOM and OpenVEX
attestations the same way:
$ cosign verify-attestation --type cyclonedx --certificate-identity-regexp "$IDENTITY" \
--certificate-oidc-issuer "$ISSUER" agledger/agledger:$VERSION
$ cosign verify-attestation --type openvex --certificate-identity-regexp "$IDENTITY" \
--certificate-oidc-issuer "$ISSUER" agledger/agledger:$VERSION
The image also carries the result of a ClamAV known-malware scan of its shipping filesystem.
cosign verify-attestation checks the signature and the predicate type, not the field values, so
assert the result yourself:
$ cosign verify-attestation --type https://agledger.ai/attestations/malware-scan/v1 \
--certificate-identity-regexp "$IDENTITY" --certificate-oidc-issuer "$ISSUER" \
agledger/agledger:$VERSION \
| jq -e '.payload | @base64d | fromjson | .predicate.result == "no-detections"'
For the SLSA Build L3 provenance, verify by digest with
slsa-verifier:
$ slsa-verifier verify-image "agledger/agledger@$(crane digest agledger/agledger:$VERSION)" \
--source-uri github.com/agledger-ai/agledger-api \
--builder-id 'https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@refs/tags/v2.1.0'
The --source-uri value is an identity check against the provenance in the public
transparency log, not a fetch: it names the repository the build ran from, and
verification succeeds without any access to it.
Docker Hub is the authoritative customer registry. Provenance binds to Docker Hub digests. Internal ECR or other registry mirrors are separate builds and will not digest-match. Verify against Docker Hub, then mirror the verified digest.
npm packages
npm audit signatures verifies both the registry signature and the Sigstore
build-provenance attestation against the public transparency log. It audits the dependency tree
of the project it runs in, so install the package into a project rather than globally:
$ npm init -y >/dev/null
$ npm install @agledger/verify-core # or any @agledger/* package
$ npm audit signatures
audited 2 packages in 0s
2 packages have verified registry signatures
2 packages have verified attestations
The count covers every package in the tree, dependencies included.
Each package page on npmjs.com links the provenance to the exact GitHub Actions run and source commit that built it.
The CycloneDX SBOM is a signed attestation over the published tarball, held in the package's
public GitHub repository (agledger-ai/verify, verify-core, sdk, cli or mcp-server).
Verify it with the GitHub CLI, which exits 0 on a match:
$ npm pack @agledger/verify@2.0.0
$ gh attestation verify agledger-verify-2.0.0.tgz --repo agledger-ai/verify \
--predicate-type https://cyclonedx.org/bom
PyPI package
agledger is published via PyPI Trusted Publishing with PEP 740 digital attestations,
which bind each release to the agledger-ai/sdk-python publishing workflow (Sigstore
identity, public Rekor). Inspect them with the
pypi-attestations tool or the PyPI
Integrity API:
$ pip install pypi-attestations
$ pypi-attestations verify pypi --repository https://github.com/agledger-ai/sdk-python \
pypi:agledger-3.0.0-py3-none-any.whl
The pypi: argument names the released file, not a requirement spec; use the wheel
filename of the PyPI release you are verifying.
(The Python SDK versions independently of the Server, so its version differs from
$VERSION above.)
What else ships with every release
-
CycloneDX SBOM and OpenVEX are bound to the image as cosign attestations (verified above) and attached for direct download to every
agledger-ai/installGitHub release (agledger-<version>-sbom.cdx.json,agledger-<version>-vex.openvex.json). -
A conformance corpus (
agledger-<version>-conformance-corpus.tar.gz, its.sha256and a.sigstore.jsonbundle) ships on every release: the real-engine vectors the offline verifiers are held to. The bundle proves the corpus came from the release workflow:$ cosign verify-blob --bundle agledger-$VERSION-conformance-corpus.tar.gz.sigstore.json \ --certificate-identity-regexp "$IDENTITY" --certificate-oidc-issuer "$ISSUER" \ agledger-$VERSION-conformance-corpus.tar.gz -
An offline verification bundle (
agledger-<version>-offline-verification.tar.gz, with.sha256and.sigstore.json), from v1.8.0, carries the signature and attestation bundles and the Sigstore trust root, so a host with no network can verify the image. Check its owncosign verify-blobthe same way while a network is still reachable, before carrying it in.
Related, but a different question
This page verifies the artifacts you install. To verify the records a running Server produces (the hash-chained, signed audit chain) offline and with nothing but the published public keys, see Audit & Verification. The vault signing-key rotation procedure is in day-2 operations.
The image and chart recipes above mirror the
install repository's SECURITY.md.
Verifying on an air-gapped host, from the offline verification bundle with
scripts/verify-release.sh, is in the install repository's
air-gap/README.md.