Skip to content

Export Sigstore bundle retrieval, offline verification, and identity extraction from container/verifier #176

Description

@samuv

Summary

RFC THV-0080 (project-level skills lock file, merged) needs to extend Sigstore signature verification to skill OCI artifacts and git commits, reusing this package's existing sigstore-go integration (currently used for MCP server image verification) rather than building a second, independent implementation.

The toolhive pkg/skills/verifier package (Stack 2 of the RFC's implementation, building on the lock-file stack currently in review — see stacklok/toolhive#5894 onward) is designed as a thin wrapper over container/verifier, per the RFC's own design section:

Extend toolhive-core's existing container/verifier package (sigstore-go, already used for MCP image verification in thv run --image-verification) for skill OCI referrers.

Today, container/verifier's bundle-retrieval, offline-verification, and identity-extraction internals (bundleFromSigstoreSignedImage, bundleFromAttestation, sigstoreBundle, signerIdentityFromCertificate, compareBaseProperties in sigstore.go/attestations.go/verifier.go) are all unexported. Sigstore.VerifyServer only supports the MCP-image online-verification flow; there's no way for a caller to fetch a bundle for storage or re-verify one offline against the embedded TUF trust roots.

Requested API

Three additions to container/verifier, keeping the same package (not a new one) since they operate on the same sigstoreBundle/TUF-trust-root machinery already there:

  1. Bundle retrieval — for storing a verified bundle alongside a skill's local install state, so sync --check can re-verify offline later without re-pulling from the registry:

    // RetrieveBundles fetches every Sigstore bundle attached to imageRef (as a
    // cosign signature-manifest layer or an OCI referrer/attestation), covering
    // both discovery mechanisms container/verifier already understands.
    func RetrieveBundles(ctx context.Context, imageRef string, keychain authn.Keychain) ([]Bundle, error)
    
    // Bundle is a retrieved Sigstore bundle: the parsed form for immediate use,
    // and canonical serialized bytes (protojson) for durable storage.
    type Bundle struct {
        Parsed *bundle.Bundle
        Raw    []byte
    }
  2. Offline verification — re-verify a stored bundle against the embedded TUF trust roots without contacting Rekor, for a hermetic CI check:

    // VerifyBundleOffline verifies bundleBytes (as produced by RetrieveBundles)
    // against artifactDigest using only the embedded TUF trust roots — no
    // network access, suitable for CI.
    func (s *Sigstore) VerifyBundleOffline(bundleBytes []byte, artifactDigest string) (*verify.VerificationResult, error)
  3. Identity extraction — recover the publisher identity from a verification result, for TOFU-pinning in a lock file:

    // Identity is the Sigstore-verified publisher identity extracted from a
    // Fulcio certificate.
    type Identity struct {
        SignerIdentity      string
        CertIssuer          string
        SourceRepositoryURI string
    }
    
    // IdentityFromResult extracts Identity from a completed verification result.
    func IdentityFromResult(result *verify.VerificationResult) (Identity, error)

Scope notes

  • Gitsign (git commit signature) verification is explicitly out of scope for this issue — it's git-specific with no container/OCI coupling, so it will live directly in toolhive's pkg/skills/verifier rather than here.
  • Catalog-supplied expected identity (matching a registry-declared publisher identity at first install, vs. today's trust-on-first-use) is also out of scope — tracked as separate follow-up work once registry/types.Skill (or similar) gains a Provenance field.
  • This is a blocking prerequisite for the toolhive-side pkg/skills/verifier PR (first PR of RFC THV-0080's Stack 2, filed after Stack 1 — currently #5892 through #5897 — is fully merged). A toolhive-core release + go.mod bump will be needed before that PR can land.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-triageIssue needs initial triage by a maintainer

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions