Resolve Docker images in a docker-compose file to their exact source code commits on GitHub.
Available as both a Python package and a Node.js package.
Node.js:
npm install -g code-provenancePython:
pip install code-provenancePoint it at a SecretVM machine and it fetches the running docker-compose and resolves every image:
code-provenance secretai-jedi.scrtlabs.comOr resolve a local docker-compose.yml:
version: "3"
services:
web:
image: traefik:v3.6.0code-provenance --workload docker-compose.ymlOutput:
web: traefik:v3.6.0
repo: github.com/traefik/traefik
commit: 06db5168c0d9
status: resolved
confidence: exact
url: https://github.com/traefik/traefik/commit/06db5168c0d9...
The tool resolves each Docker image through a chain of strategies, stopping at the first success:
- OCI labels -- reads
org.opencontainers.image.sourceandorg.opencontainers.image.revisionfrom the image manifest - Repo inference -- maps the image registry/namespace to a GitHub repository (GHCR namespaces map directly; Docker Hub images are resolved via the Hub API)
- Tag matching -- matches the Docker tag against git tags in the inferred repository
- Packages API -- for GHCR images, queries the GitHub Packages API to resolve digests or
:latesttags - Latest release / commit -- for
:latesttags, falls back to the most recent GitHub release or the HEAD commit on the default branch
- exact -- the commit is definitively tied to the image (e.g., OCI revision label with a versioned tag, or an exact git tag match)
- approximate -- the commit is a best-effort match (e.g.,
:latesttag, prefix tag match, or latest release fallback)
code-provenance [machine-url] [--workload FILE] [--image IMAGE] [--json] [--verbose]| Argument | Description |
|---|---|
machine-url |
SecretVM machine URL or hostname (e.g. secretai-jedi.scrtlabs.com). The docker-compose is fetched from it over port 29343, falling back to 21434 for GPU machines. |
--workload FILE |
Resolve a local docker-compose file instead of a machine URL |
--image IMAGE |
Resolve a single image reference |
--secretvm URL |
SecretVM machine URL (same as passing it positionally; kept for backward compatibility) |
--json |
Output results as JSON |
--verbose, -v |
Show the resolution steps for each image |
# Resolve all images running on a SecretVM machine (default mode)
code-provenance secretai-jedi.scrtlabs.com
# Resolve all images in a local compose file
code-provenance --workload docker-compose.yml
# Resolve a single image
code-provenance --image ollama/ollama:0.12.3
# JSON output
code-provenance secretai-jedi.scrtlabs.com --json
# Show resolution steps
code-provenance --workload docker-compose.yml --verboseThe tool works without authentication for basic resolution (OCI labels, tag matching). However, a GITHUB_TOKEN is required for:
- Resolving digest-only images (e.g.,
image@sha256:...) via the GitHub Packages API - Resolving
:latesttags on GHCR images via the Packages API - Higher GitHub API rate limits (5000/hr vs 60/hr unauthenticated)
Option 1 — Use the gh CLI (recommended): If you have the GitHub CLI installed and authenticated, run.sh auto-detects the token. Make sure your token has read:packages scope:
gh auth refresh -h github.com -s read:packagesOption 2 — Set the environment variable directly:
export GITHUB_TOKEN=ghp_your_token_hereCreate a classic token at https://github.com/settings/tokens with read:packages scope.
Both packages export the same API for programmatic use.
Node.js:
import { parseCompose, parseImageRef, resolveImage } from "code-provenance";
import { readFileSync } from "fs";
const yaml = readFileSync("docker-compose.yml", "utf-8");
for (const [service, image] of parseCompose(yaml)) {
const ref = parseImageRef(image);
const result = await resolveImage(service, ref);
console.log(`${result.service}: ${result.commit} (${result.confidence})`);
}Python:
from code_provenance.compose_parser import parse_compose, parse_image_ref
from code_provenance.resolver import resolve_image
yaml_content = open("docker-compose.yml").read()
for service, image in parse_compose(yaml_content):
ref = parse_image_ref(image)
result = resolve_image(service, ref)
print(f"{result.service}: {result.commit} ({result.confidence})")See python/README.md and node/README.md for full API reference.
MIT