Skip to content

Verifying a release

This page covers the customer-local bundle and the signed manifest that comes with it. The open source server has none of this: it is a public repository you clone and build, with nothing to verify and no credential to hold.

The point of the exercise is ordering. You verify the release before you hold a registry credential and before you extract anything of ours, so the check does not depend on anything we gave you except a signature you can trace to a public workflow run.

Four files, published together in a per-version directory under /releases/.

FileWhat it is
metergraph-customer-local-<version>.tar.gzThe bundle: bin/, docker-compose.yml, .env.example. No images, no data, no credential
metergraph-byoc-release.jsonThe manifest. It records the bundle’s SHA-256, both image repositories and their exact digests, and the platforms published for this release
metergraph-byoc-release.json.sigThe detached signature over the manifest
metergraph-byoc-release.json.pemThe certificate the signature was made with

No account or credential is needed to fetch any of them, which is the whole design: the value is in the private images, so the thing that proves what the images are can be public.

  1. Sigstore’s installation guide covers every platform. On macOS:

    brew install cosign
  2. base=https://www.metergraph.dev/releases/<version>
    curl -fsSLO "$base/metergraph-customer-local-<version>.tar.gz"
    for f in metergraph-byoc-release.json{,.sig,.pem}; do curl -fsSLO "$base/$f"; done
  3. cosign verify-blob \
    --certificate metergraph-byoc-release.json.pem \
    --signature metergraph-byoc-release.json.sig \
    --certificate-oidc-issuer https://token.actions.githubusercontent.com \
    --certificate-identity-regexp '^https://github\.com/PioneerSquareLabs/metergraph-internal/\.github/workflows/byoc-release\.yml@refs/(heads/main|tags/v.+)$' \
    metergraph-byoc-release.json

    This is keyless signing, so there is no public key to distribute and trust. What is pinned instead is the identity: the repository, the exact workflow file byoc-release.yml, and GitHub’s OIDC issuer. Only the git ref is matched loosely, because a published release runs the workflow on its tag while the same workflow can be dispatched from the default branch.

    A signature made by any other workflow, in any other repository, fails here.

  4. Check the bundle against the verified manifest

    Section titled “Check the bundle against the verified manifest”

    The manifest records the bundle’s own checksum, so verifying the manifest also authenticates the archive. Read the expected value out of the manifest rather than off a web page, so the two cannot disagree:

    python3 - <<'EOF'
    import hashlib, json, sys
    manifest = json.load(open("metergraph-byoc-release.json"))
    name = manifest["local_bundle"]
    actual = hashlib.sha256(open(name, "rb").read()).hexdigest()
    if actual != manifest["local_bundle_sha256"]:
    sys.exit(f"{name} does not match the signed manifest. Do not run it.")
    print(f"{name} matches the signed manifest.")
    EOF

    Releases cut before the manifest carried local_bundle_sha256 have no bundle checksum to check. Their release page omits this step rather than describing a check the manifest cannot support.

  5. Extract, and move the manifest in beside it

    Section titled “Extract, and move the manifest in beside it”
    tar xzf metergraph-customer-local-<version>.tar.gz
    mv metergraph-byoc-release.json* local/
    cd local

    The three metergraph-byoc-release.json* files must end up inside local/, next to bin/start. If they do not, bin/start stops with error: metergraph-byoc-release.json not found.

From here, follow the customer-local bundle: registry login, .env, ./bin/start.

The manual check above proves the archive. bin/start then repeats and extends the proof each time it runs, using the same trust anchor.

  1. All three manifest files are present, or it exits before doing anything.
  2. cosign verify-blob over the manifest, with the same issuer and identity pattern you used by hand.
  3. Your host architecture is one of the manifest’s local_platforms, so a release that was never published for this machine fails clearly instead of pulling something that cannot run.
  4. Both image references are resolved from the manifest, and a reference is refused unless the digest matches sha256: plus 64 hex characters. A tag-shaped reference is a hard error. There is no fall back to a mutable tag, ever.
  5. cosign verify on each resolved image, against that same identity.

Only then are the digests written to .images.env and handed to Compose, which reads that file last so a stray METERGRAPH_APP_IMAGE in your .env cannot override a verified digest.

Verification tells you exactly which images you are about to run. Pulling them still needs the registry user and token that came with your invitation. Ask your Metergraph contact if you do not have them.

That split is deliberate. Everything needed to decide whether to trust a release is public. Only the artifact itself is not.