Skip to content

Track: Skills lock file + Sigstore signing (RFC THV-0080) #5899

Description

@samuv

Summary

Tracks the productionized implementation of RFC THV-0080: a project-level toolhive.lock.yaml that pins every project-scoped skill install (source, resolvedReference, digest, contentDigest, Sigstore provenance), plus thv skill sync / thv skill upgrade, signature verification on consume, and signing on push.

This replaces the original POC, PR #5715 (closed), which validated the approach but was too large to review/merge as one diff. The author's follow-up comment proposed a 14-PR split across two stacks; this issue tracks that split end-to-end.

The feature is gated behind TOOLHIVE_SKILLS_LOCK_ENABLED for the whole rollout — it stays inert on main until both stacks land, since the RFC treats reproducible pinning and Sigstore verification as one "v1" trust model, not two independently shippable halves.

Stack 1 — Lock file mechanics (✅ fully merged 2026-07-24)

Branch chain: skills-lock/01-lockfile → ... → skills-lock/06-cli-exitcodes, each PR targeting the previous one's branch.

Each PR includes its own tests (unit + E2E where applicable) and passes CI independently of the rest of the stack. A local review pass caught and fixed 6 correctness bugs across this stack before human review (digest-forgery via crafted paths, an unvalidated lock-file write path, an incomplete install rollback, inconsistent dependency-cycle keying, a sync-triggered field corruption, and a --fail-on-changes gate that mutated state before failing) — see each PR's commit history for details.

Stack 2 — Sigstore signing/verification (8 of 10 merged)

Branch chain: skills-sig/07-provenance-schema → ... → skills-sig/14-push-signing-ungate.

Current state: verification is fully implemented and released (v0.42.1), but the
feature remains gated on mainpkg/skills/feature_gate.go and six
LockFileFeatureEnabled() call sites are still present, so users see nothing unless
they set TOOLHIVE_SKILLS_LOCK_ENABLED. #6139 is what removes that, and it is still
open. #6139 is stacked on #6137's branch, so #6137 lands first.

Validated end-to-end

stacklok/toolhive-skills-lock-example exercises the merged half against the real
catalog: a dockyard-signed skill is installed, its keyless Sigstore signature verified,
the observed identity TOFU-pinned into toolhive.lock.yaml, and a scheduled workflow
detects upstream drift and opens a PR. Building it surfaced four bugs, all fixed and
released in v0.42.1 — #6211, #6212, #6213, plus the thv ai-plugin counterparts of the
first two.

Follow-ups (tracked separately once reached)

  • Keyless push signing + Sigstore-staging E2E
  • Catalog-supplied expected identity (needs toolhive-core Provenance on Skill types)
  • Move pkg/skills/signer into toolhive-core next to the verification exports, so all
    Sigstore code lives in one place (decided 2026-07-28, sequenced after PR14 because
    Sign pushes by default and remove the lock feature gate #6139 still modifies the package). The package imports nothing from toolhive, so the
    move is mechanical.
  • verifier: simple-signing payload digest binding is not independently validated toolhive-core#198 — the simple-signing payload digest binding is not
    independently validated; affects the verify path this stack depends on.
  • Record the certificate's source ref and runner environment in lock provenance. The
    recorded identity currently pins repository + workflow file but not the git ref, so a
    signature produced by that workflow on any branch satisfies the policy.

Definition of done

  • All Stack 1 PRs merged with CI green (including CodeQL).
  • toolhive-core#176 released and consumed via a go.mod bump.
  • All Stack 2 PRs merged.
  • TOOLHIVE_SKILLS_LOCK_ENABLED gate removed in PR14, documented as the user-facing change.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestskillsSkills lifecycle management

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions