neuralmind.uk / Verify a NeuralMind release before installing it Edit this page on GitHub ↗

Verify a NeuralMind release before installing it

Goal: before a NeuralMind wheel or container image goes onto a developer machine, a build agent or an enclave, check that the release’s own GitHub workflow built it from this repository, and know what is inside it.

Who this is for: security reviewers, platform teams that mirror packages internally, and anyone who has to answer the supply-chain questions in a vendor review: who built it, from what, with what dependencies, and which advisories apply. neuralmind.uk/security gives these commands with the latest release filled in. This page explains each one: what it proves, what it doesn’t, and what a failure looks like.

What you can verify: every release from v4.14.0 on. Earlier releases were not signed and have no attestation to check.

Set the version once. The examples use v4.20.0:

V=4.20.0

You need cosign for the container image and the GitHub CLI (gh, logged in to any account) for attestations. Neither needs access to anything beyond the public repository.


1. The container image: signed by the release workflow

cosign verify ghcr.io/dfrostar/neuralmind:v$V \
  --certificate-identity-regexp '^https://github\.com/dfrostar/neuralmind/\.github/workflows/docker-publish\.yml@refs/(heads/main|tags/v[0-9]+\.[0-9]+\.[0-9]+)$' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

What it proves: the image digest the tag points to was signed, keyless, by docker-publish.yml in dfrostar/neuralmind, running from main or a version tag. The signature is recorded in Sigstore’s public transparency log. Signing uses no long-lived key that could leak. Each signature is bound to the identity of the workflow run that made it.

Why the long pattern: it pins both the workflow file and the git ref it ran from. A signature made by the same workflow on any other branch, such as a pull request or a fork, fails it. Checking only the repository would accept that signature.

On failure cosign prints no matching signatures and exits non-zero. Don’t pull the image. If you mirror images, verify by digest and mirror that digest. A tag can be moved; the digest you verified can’t.

2. The image’s build provenance

gh attestation verify oci://ghcr.io/dfrostar/neuralmind:v$V --repo dfrostar/neuralmind \
  --cert-identity-regex '^https://github\.com/dfrostar/neuralmind/\.github/workflows/docker-publish\.yml@refs/(heads/main|tags/v[0-9]+\.[0-9]+\.[0-9]+)$'

What it proves: a signed SLSA build-provenance statement for this image names the workflow, the commit and the runner that built it. Add --format json to keep it as evidence.

Check the commit against the tag. The commit in the provenance is the one the workflow ran from, not necessarily the one it checked out. release-please starts the release workflows from main right after it merges the release commit, and they check out the version tag. So the two match unless main moved in between, or someone re-ran a release by hand later. Compare them:

gh attestation verify oci://ghcr.io/dfrostar/neuralmind:v$V --repo dfrostar/neuralmind \
  --cert-identity-regex '^https://github\.com/dfrostar/neuralmind/\.github/workflows/docker-publish\.yml@refs/(heads/main|tags/v[0-9]+\.[0-9]+\.[0-9]+)$' \
  --format json | jq -r '.[0].verificationResult.statement.predicate.buildDefinition.resolvedDependencies[0].digest.gitCommit'
gh api repos/dfrostar/neuralmind/commits/v$V --jq .sha

The two hashes should be the same. If they differ, the attestation proves which workflow run built the image, but not that it built it from the tagged commit. Ask before you deploy it.

The release workflow runs steps 1 and 2 against every image it publishes, and stops before :latest moves if either fails. You are re-running a check the release already passed, on your own machine and against what you actually pulled.

3. The wheel or sdist from PyPI

pip download --no-deps neuralmind==$V -d dist/
gh attestation verify dist/neuralmind-$V-py3-none-any.whl --repo dfrostar/neuralmind \
  --cert-identity-regex '^https://github\.com/dfrostar/neuralmind/\.github/workflows/release\.yml@refs/(heads/main|tags/v[0-9]+\.[0-9]+\.[0-9]+)$'

What it proves: the file you downloaded is byte-for-byte the one release.yml built, because the attestation is over its SHA-256. The sdist (neuralmind-$V.tar.gz, from pip download --no-binary :all: --no-deps) has its own attestation and is checked the same way. PyPI also holds the PEP 740 attestations that trusted publishing uploads. The commit check in step 2 works the same way here: pass --format json and compare the commit with the tag’s.

Install what you verified:

pip install --no-deps dist/neuralmind-$V-py3-none-any.whl

Use --no-deps only if you install the dependencies separately (for example from your own mirror). Otherwise drop it. pip then resolves the dependencies from your index, at whatever versions it finds that day. NeuralMind’s attestation doesn’t cover them, and step 4’s SBOM may not match them either. Scan the environment you actually installed.

4. What’s inside: the SBOM

Every release since v4.0.0 has a CycloneDX SBOM. Releases on this repository are immutable, so the SBOM can’t be attached to them after they are published. It is served from the site instead:

curl -fsSLO https://neuralmind.uk/sbom/neuralmind-v$V.sbom.json

It lists neuralmind itself and every package a default install brought in, with versions and package URLs. Read it for what it is: one install, on Linux, on release day. The workflow runs pip install . at the tag on an Ubuntu runner and records the result. Two things can make your install differ:

The SBOM is still the record of what NeuralMind shipped against. Load it into the tool you already use (Dependency-Track, Grype, Trivy), or scan it directly:

grype sbom:neuralmind-v$V.sbom.json
# or
trivy sbom neuralmind-v$V.sbom.json

What it doesn’t prove: an SBOM says what one install of a release contained. Steps 1 to 3 show you have that release. For what is on your machine, scan the environment itself, after installing:

grype dir:/path/to/venv
# or
pip-audit        # inside the activated environment

5. Which advisories don’t apply: the VEX

security/neuralmind.openvex.json is an OpenVEX document. It lists the advisories in NeuralMind’s dependencies that NeuralMind is not affected by, each with the reason. Today those are four ChromaDB advisories. NeuralMind uses only ChromaDB’s local, on-disk PersistentClient and never starts ChromaDB’s server.

They matter when you scan an environment that has chromadb in it: the default install on Intel macOS and Windows on ARM, or any install with the chromadb extra. Pass the VEX with the scan, and those advisories show as not affected, with the reason, instead of open:

curl -fsSLO https://raw.githubusercontent.com/dfrostar/neuralmind/main/security/neuralmind.openvex.json
grype dir:/path/to/venv --vex neuralmind.openvex.json
# or
trivy fs /path/to/venv --vex neuralmind.openvex.json

The VEX is a living statement, so it is read from main, not from a release tag. Three checks keep it honest. CI’s pip-audit ignores exactly the advisories it lists, so any other advisory fails the build. A test fails if an entry has no argument in SECURITY.md. And when ChromaDB ships a fix, a watch workflow opens an issue, and the statement comes out of the VEX.

6. Put it on file

For a vendor review or a System Security Plan, keep:

Evidence From
cosign verify output (JSON) for the image digest you deployed Step 1
The provenance statement (gh attestation verify … --format json) Steps 2 and 3
The SBOM for that version Step 4
The VEX as of the date you assessed Step 5
The SSDF mapping: every NIST SP 800-218 practice, mapped to the workflow, file or check that is its evidence The repository

The same commands are in SSDF.md §2. If the release is going onto a machine with no network, verify it on the connected side before it crosses: Run NeuralMind air-gapped. For an enclave, continue with Use NeuralMind in a CMMC CUI enclave, and run neuralmind hardening on the host after installing.

What this doesn’t cover