Problem
Skills can carry provenance constraints on their registry entry (regtypes.Skill.Provenance, RFC THV-0080 follow-up #6310, verifier support in #6420). On true first use of a skill resolved from a catalog, skillsvc.verifyOCIInstall enforces the catalog-declared signer_identity / cert_issuer / repository_uri / repository_ref / runner_environment via verifier.NewCatalogExpectation, and refuses to install under a --public-key when the catalog declares a certificate identity.
Plugins have none of this. toolhive-core/registry/types/plugins_types.go has no Provenance field, plugins.InstallOptions has no CatalogProvenance, and pluginsvc.verifyOCIInstall presents only a lock expectation (NewLockExpectation(expected), nil on TOFU). The resolveKeyAnchor comment in pkg/plugins/pluginsvc/verify.go records this as the one deliberate divergence from skills.
With #6442 closed, this is the last trust-model asymmetry between the two surfaces. It matters more for plugins than for skills: a plugin contributes hooks and MCP servers to the client that loads it, so a first install that trusts whatever identity it observes is the larger blast radius.
Proposed scope
toolhive-core: add Provenance *Provenance to the plugin registry entry type, reusing the existing certificate-shaped regtypes.Provenance (needs a core release and a go.mod bump here).
plugins.InstallOptions.CatalogProvenance (internal, json:"-"), hydrated by the registry-resolving install path.
pluginsvc.verifyOCIInstall / verifyGitInstall: on true first use (no lock entry), build the expectation with verifier.NewCatalogExpectation(normalizeCatalogProvenance(...)), reject unsupported constraints (sigstore_url, attestation) with 422 as validateCatalogProvenance does, and classify failures via a classifyCatalogVerifyError mirror.
resolveKeyAnchor gains the catalog arm: a supplied --public-key against a catalog entry that declares a certificate identity is a 403, exactly as on skills.
- Lock precedence is unchanged: any existing lock entry, including a legacy one with no trust state, wins over the catalog.
- Tests mirroring
skillsvc's catalog tests; arch doc update in 14-plugins-system.md#trust-model.
Related
Problem
Skills can carry provenance constraints on their registry entry (
regtypes.Skill.Provenance, RFC THV-0080 follow-up #6310, verifier support in #6420). On true first use of a skill resolved from a catalog,skillsvc.verifyOCIInstallenforces the catalog-declaredsigner_identity/cert_issuer/repository_uri/repository_ref/runner_environmentviaverifier.NewCatalogExpectation, and refuses to install under a--public-keywhen the catalog declares a certificate identity.Plugins have none of this.
toolhive-core/registry/types/plugins_types.gohas noProvenancefield,plugins.InstallOptionshas noCatalogProvenance, andpluginsvc.verifyOCIInstallpresents only a lock expectation (NewLockExpectation(expected), nil on TOFU). TheresolveKeyAnchorcomment inpkg/plugins/pluginsvc/verify.gorecords this as the one deliberate divergence from skills.With #6442 closed, this is the last trust-model asymmetry between the two surfaces. It matters more for plugins than for skills: a plugin contributes hooks and MCP servers to the client that loads it, so a first install that trusts whatever identity it observes is the larger blast radius.
Proposed scope
toolhive-core: addProvenance *Provenanceto the plugin registry entry type, reusing the existing certificate-shapedregtypes.Provenance(needs a core release and ago.modbump here).plugins.InstallOptions.CatalogProvenance(internal,json:"-"), hydrated by the registry-resolving install path.pluginsvc.verifyOCIInstall/verifyGitInstall: on true first use (no lock entry), build the expectation withverifier.NewCatalogExpectation(normalizeCatalogProvenance(...)), reject unsupported constraints (sigstore_url,attestation) with 422 asvalidateCatalogProvenancedoes, and classify failures via aclassifyCatalogVerifyErrormirror.resolveKeyAnchorgains the catalog arm: a supplied--public-keyagainst a catalog entry that declares a certificate identity is a 403, exactly as on skills.skillsvc's catalog tests; arch doc update in14-plugins-system.md#trust-model.Related
--keypush signing has no install-time verification path (plugins) #6442 (key path; theresolveKeyAnchorcatalog arm is the one piece plugins skipped)