Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/arch/12-skills-system.md
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,10 @@ RFC [THV-0080](https://github.com/stacklok/toolhive-rfcs/blob/main/rfcs/THV-0080

**Trust model, stated plainly:** project-scoped installs are verified against Sigstore signatures, and the lock file records the trust decisions those verifications produce. On first install of a signed skill the observed signer identity is recorded (trust on first use) as the entry's `provenance:` block and **displayed to the user**; every later install, sync, and upgrade enforces that identity *inside* the Sigstore verification policy — OCI artifacts through their attached signature bundles, git commits through gitsign signature-and-chain verification (currently `provisional: true`: the transparency-log proof of signing time is not yet validated, so the replay window is unbounded until that lands). Sync additionally re-verifies each entry's stored signature bundle offline (embedded trust root, no network) before counting it current, and upgrade refuses to move to an artifact signed by a different identity — or unsigned — without an explicit `--allow-signer-change`.

**First install need not be blind.** When a skill resolves through the registry/catalog (a plain name like `thv skill install code-review`, not a direct OCI or git reference) and that catalog entry declares an expected `provenance` (`toolhive-core`'s `registry.Skill.Provenance`, RFC THV-0080 follow-up [#6310](https://github.com/stacklok/toolhive/issues/6310)), the very first project-scoped install is checked against it instead of unconditionally trusting whatever the artifact's signature says. Each non-empty supported field constrains independently; an empty or absent catalog provenance preserves ordinary trust on first use. For multi-signed OCI artifacts, every cryptographically valid signature is considered until one satisfies all declared constraints. A lock entry, including a legacy entry with no recorded trust state, always takes precedence over the catalog — the catalog only fills the gap before any trust decision has been recorded. User-scoped installs do not use project lock-file verification and therefore do not apply catalog provenance.

Catalog constraints the skill verifier cannot enforce are refused rather than silently skipped. Attestations are not yet compared, and `sigstore_url` selects trust material in the registry schema while the skill verifier currently uses its embedded public-good trust root. A non-empty `sigstore_url` or any declared `attestation` therefore fails a true first project install; existing lock entries remain authoritative.

The Sigstore policy alone is not the whole guarantee: its SAN match deliberately leaves the signing workflow's git ref unpinned (`(@.*)?$`), so identity alone is satisfied by "the right workflow, on any branch." Two additional certificate fields — the git ref the signing workflow ran on and the runner class it executed in (`repositoryRef:`/`runnerEnvironment:` in `provenance:`) — are enforced separately, after the Sigstore policy succeeds, against the certificate's Fulcio extensions. An entry recorded before these fields existed, or a certificate that carries neither (a signer outside CI), is unconstrained on that field — never a wildcard match once something IS recorded. Install, sync, and upgrade all require the recorded ref and runner class to match exactly, with no automatic allowance for any kind of change, ref rotation included: an earlier version of this guard let a recorded tag ref rotate to any other tag ref automatically, reasoning that a release workflow signs each version on its own tag, but review found that this let a candidate signed from an attacker's own tag on the same repository (e.g. `refs/tags/attacker-release`) replace a pinned tag just as easily, since nothing tied the candidate's tag to the version actually being upgraded to. A ref or runner-class change of any shape is now blocked exactly like a genuine signer-identity change, and needs the same explicit `--allow-signer-change` to proceed and re-record it.

What is still trusted on faith, deliberately and visibly:
Expand Down
5 changes: 4 additions & 1 deletion docs/server/docs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion docs/server/swagger.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 16 additions & 1 deletion docs/server/swagger.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

82 changes: 42 additions & 40 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ require (
github.com/1password/onepassword-sdk-go v0.3.1
github.com/alicebob/miniredis/v2 v2.38.0
github.com/atotto/clipboard v0.1.4
github.com/aws/aws-sdk-go-v2 v1.43.5
github.com/aws/aws-sdk-go-v2/config v1.32.36
github.com/aws/aws-sdk-go-v2/service/sts v1.45.5
github.com/aws/aws-sdk-go-v2 v1.43.7
github.com/aws/aws-sdk-go-v2/config v1.32.38
github.com/aws/aws-sdk-go-v2/service/sts v1.45.7
github.com/cedar-policy/cedar-go v1.8.0
github.com/cenkalti/backoff/v5 v5.0.3
github.com/charmbracelet/bubbles v1.0.0
Expand All @@ -20,13 +20,12 @@ require (
github.com/coreos/go-oidc/v3 v3.20.0
github.com/docker/go-connections v0.7.0 // indirect
github.com/evanphx/json-patch/v5 v5.9.11
github.com/go-chi/chi/v5 v5.3.0
github.com/go-chi/chi/v5 v5.3.1
github.com/go-git/go-billy/v5 v5.9.0
github.com/go-git/go-git/v5 v5.19.2
github.com/go-jose/go-jose/v3 v3.0.5
github.com/go-jose/go-jose/v4 v4.1.4
github.com/gofrs/flock v0.13.0
github.com/google/cel-go v0.31.0
github.com/google/go-cmp v0.7.0
github.com/google/go-containerregistry v0.21.9
github.com/google/uuid v1.6.0
Expand All @@ -49,8 +48,8 @@ require (
github.com/shirou/gopsutil/v4 v4.26.7
github.com/spf13/viper v1.21.0
github.com/stacklok/toolhive-catalog v0.20260817.0
github.com/stacklok/toolhive-core v0.0.41
github.com/stretchr/testify v1.11.1
github.com/stacklok/toolhive-core v0.0.42
github.com/stretchr/testify v1.12.1
github.com/swaggo/swag/v2 v2.0.0-rc5
github.com/tailscale/hujson v0.0.0-20260727124030-b80ff77dac4f
github.com/testcontainers/testcontainers-go v0.42.0
Expand Down Expand Up @@ -85,25 +84,29 @@ require github.com/getsentry/sentry-go/otel v0.44.1
require github.com/hashicorp/golang-lru/v2 v2.0.7

require (
cel.dev/cel-go v0.32.0
github.com/github/smimesign v0.2.0
go.starlark.net v0.0.0-20260630144053-529d8e869a14
)

require (
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.37 // indirect
github.com/go-openapi/runtime/server-middleware v0.30.0 // indirect
github.com/go-openapi/swag/pools v0.27.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.39 // indirect
github.com/go-openapi/runtime/server-middleware v0.33.1 // indirect
github.com/go-openapi/swag/pools v0.28.0 // indirect
github.com/jedisct1/go-minisign v0.0.0-20241212093149-d2f9f49435c7 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c // indirect
github.com/modelcontextprotocol/go-sdk v1.7.0 // indirect
github.com/oklog/ulid/v2 v2.1.1 // indirect
github.com/oklog/ulid/v2 v2.1.2 // indirect
github.com/oleiade/reflections v1.1.0 // indirect
github.com/sassoftware/relic v7.2.1+incompatible // indirect
github.com/sassoftware/relic/v8 v8.2.0 // indirect
github.com/segmentio/encoding v0.5.4 // indirect
github.com/theupdateframework/go-tuf v0.7.0 // indirect
github.com/valyala/fastjson v1.6.10 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.21.0 // indirect
go.opentelemetry.io/otel/log v0.21.0 // indirect
go.opentelemetry.io/otel/sdk/log v0.21.0 // indirect
)

require (
Expand All @@ -114,19 +117,18 @@ require (
github.com/ProtonMail/go-crypto v1.4.1 // indirect
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.19.35 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.36 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.36 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.36 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.16 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.36 // indirect
github.com/aws/aws-sdk-go-v2/service/signin v1.5.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.33.5 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.38.5 // indirect
github.com/aws/smithy-go v1.27.7 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.19.37 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.38 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.38 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.38 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.17 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.38 // indirect
github.com/aws/aws-sdk-go-v2/service/signin v1.5.7 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.33.7 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.38.7 // indirect
github.com/aws/smithy-go v1.27.8 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver v3.5.1+incompatible // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/charmbracelet/colorprofile v0.4.1 // indirect
Expand Down Expand Up @@ -163,27 +165,27 @@ require (
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-logr/zapr v1.3.0 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-openapi/analysis v0.25.5 // indirect
github.com/go-openapi/analysis v0.26.0 // indirect
github.com/go-openapi/errors v0.22.8 // indirect
github.com/go-openapi/jsonpointer v1.0.0 // indirect
github.com/go-openapi/jsonreference v1.0.0 // indirect
github.com/go-openapi/loads v0.25.0 // indirect
github.com/go-openapi/runtime v0.33.0 // indirect
github.com/go-openapi/loads v0.25.1 // indirect
github.com/go-openapi/runtime v0.33.1 // indirect
github.com/go-openapi/spec v0.22.9 // indirect
github.com/go-openapi/strfmt v0.27.0 // indirect
github.com/go-openapi/swag v0.26.1 // indirect
github.com/go-openapi/swag/cmdutils v0.27.0 // indirect
github.com/go-openapi/swag/conv v0.28.0 // indirect
github.com/go-openapi/swag/fileutils v0.27.3 // indirect
github.com/go-openapi/swag/conv v0.29.1 // indirect
github.com/go-openapi/swag/fileutils v0.28.0 // indirect
github.com/go-openapi/swag/jsonname v0.26.1 // indirect
github.com/go-openapi/swag/jsonutils v0.27.3 // indirect
github.com/go-openapi/swag/loading v0.27.3 // indirect
github.com/go-openapi/swag/mangling v0.27.3 // indirect
github.com/go-openapi/swag/jsonutils v0.28.0 // indirect
github.com/go-openapi/swag/loading v0.28.0 // indirect
github.com/go-openapi/swag/mangling v0.28.0 // indirect
github.com/go-openapi/swag/netutils v0.27.0 // indirect
github.com/go-openapi/swag/stringutils v0.27.3 // indirect
github.com/go-openapi/swag/typeutils v0.28.0 // indirect
github.com/go-openapi/swag/yamlutils v0.27.3 // indirect
github.com/go-openapi/validate v0.26.1 // indirect
github.com/go-openapi/swag/stringutils v0.28.0 // indirect
github.com/go-openapi/swag/typeutils v0.29.1 // indirect
github.com/go-openapi/swag/yamlutils v0.28.0 // indirect
github.com/go-openapi/validate v0.26.3 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
github.com/gobuffalo/pop/v6 v6.1.1 // indirect
Expand Down Expand Up @@ -252,12 +254,12 @@ require (
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sagikazarmark/locafero v0.12.0 // indirect
github.com/seatgeek/logrus-gelf-formatter v0.0.0-20210414080842-5b05eb8ff761 // indirect
github.com/secure-systems-lab/go-securesystemslib v0.11.0 // indirect
github.com/secure-systems-lab/go-securesystemslib v0.11.1 // indirect
github.com/sergi/go-diff v1.4.0 // indirect
github.com/sethvargo/go-retry v0.3.0 // indirect
github.com/shibumi/go-pathspec v1.3.0 // indirect
github.com/sigstore/protobuf-specs v0.5.1 // indirect
github.com/sigstore/rekor v1.5.3 // indirect
github.com/sigstore/protobuf-specs v0.5.2 // indirect
github.com/sigstore/rekor v1.5.4 // indirect
github.com/sigstore/rekor-tiles/v2 v2.3.0 // indirect
github.com/sigstore/sigstore v1.10.9
github.com/sigstore/sigstore-go v1.3.0
Expand Down Expand Up @@ -297,7 +299,7 @@ require (
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.yaml.in/yaml/v2 v2.4.4 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
go.yaml.in/yaml/v3 v3.0.5 // indirect
golang.ngrok.com/muxado/v2 v2.0.1 // indirect
golang.org/x/exp/event v0.0.0-20260611194520-c48552f49976 // indirect
golang.org/x/net v0.58.0 // indirect
Expand All @@ -308,7 +310,7 @@ require (
google.golang.org/genproto/googleapis/api v0.0.0-20260803160001-6ac0973c030d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d // indirect
google.golang.org/grpc v1.83.0 // indirect
google.golang.org/protobuf v1.36.11
google.golang.org/protobuf v1.36.12
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
Expand Down
Loading
Loading