Skip to content

Project-level skills lock file with Sigstore signing and verification #5740

Description

@samuv

User Story

As a team maintaining a project that consumes agent skills,
I want project-scope skill installs pinned in a committed lock file, cryptographically verified against the publisher's Sigstore identity, and safely upgradable,
So that every teammate and CI run restores the exact same reviewed skills, and tampered or re-signed artifacts are detected before they reach a developer's machine.

Context

RFC THV-0080 (stacklok/toolhive-rfcs#80) proposes a project-level skills lock file. PR #5715 implements a feasibility POC covering the full vertical slice:

  • Lock filetoolhive.lock.yaml pins source, resolvedReference, digest, and an on-disk contentDigest, with thv skill sync (--check/--adopt/--prune) and thv skill upgrade (--preview/--allow-ref-change)
  • Sigstore v1 trust — verify on consume (install/sync/upgrade), sign on push (--key, --no-sign), TOFU publisher identity pinned as provenance in the lock (or an explicit unsigned: true exception), offline bundle re-verification in sync --check, and a signer-change guard on upgrade (--allow-signer-change)

The POC validated feasibility (~6.6k lines / 74 files) but is intentionally not mergeable as one PR. This story tracks landing the work for production as 14 stacked PRs across two dependency chains (plan detailed in PR #5715):

Stack 1 — Lock file (6 PRs): lockfile package → SkillLockService split + storage → install/uninstall hooks → sync → upgrade → API/CLI surface

Stack 2 — Sigstore v1 (8 PRs, after Stack 1): provenance schema → verifier package → signer package → bundle storage + git signature plumbing → install verification → sync offline verify → upgrade signer guard → push signing + CLI/API flags

Each PR is independently buildable and testable (task test, task lint); this is a rewrite-by-file of the POC branch, not a cherry-pick of its commits.

Acceptance Criteria

Stack 1 — Lock file

  • AT: Project-scope thv skill install writes a toolhive.lock.yaml entry pinning source, resolvedReference, digest, and contentDigest; thv skill uninstall removes it and cascade-removes orphaned dependencies (requiredBy/explicit)
  • AT: thv skill sync --check detects drift between the lock file and installed skills (missing, digest mismatch, on-disk tampering via contentDigest) and exits with code 2 on failure
  • AT: thv skill sync --adopt records out-of-band installs into the lock; --prune removes lock entries for manually deleted skills
  • AT: thv skill upgrade --preview shows the candidate change without applying; moving to a different resolved reference requires --allow-ref-change
  • AT: Sync and upgrade are exposed via POST /skills/sync and POST /skills/upgrade with typed exit codes for CI (0 success / 2 check failure / 3 partial failure / 4 policy rejection)
  • Unit: toolhive.requires dependencies are materialized as lock entries with requiredBy tracking

Stack 2 — Sigstore v1

  • AT: Project-scope install verifies OCI artifacts via the Sigstore referrers API and git skills via gitsign; unsigned artifacts are rejected unless --allow-unsigned is passed, which records unsigned: true in the lock
  • AT: First verified install pins the publisher identity (provenance.signerIdentity + certIssuer, TOFU); subsequent installs/syncs fail with signer-mismatch if the identity diverges
  • AT: thv skill sync --check re-verifies stored Sigstore bundles offline (no registry access) against the locked provenance
  • AT: thv skill upgrade blocks candidates whose signer identity or cert issuer changed, with --allow-signer-change as the explicit override
  • AT: thv skill push signs by default with a cosign key (--key, COSIGN_PASSWORD), attaching the signature as an OCI referrer; --no-sign opts out
  • Unit: Verified bundles are persisted alongside installed skills (SQLite) for offline re-verification
  • Lock entries validate as exactly one of provenance or unsigned: true

Delivery

  • Work lands as the 14-PR stacked chain described above, each PR within repo size guidelines and independently green
  • docs/arch/12-skills-system.md documents the v1 trust model (cryptographic verification / TOFU identity / human lock-file review)

Out of Scope (deferred from v1)

  • Keyless OIDC push signing (E2E against Sigstore staging)
  • Catalog-supplied expected identity (requires Provenance on toolhive-core Skill types)

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    cliChanges that impact CLI functionalityenhancementNew feature or requestgoPull requests that update go codeskillsSkills lifecycle management

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions