sigstore/cosign
pkg/providers
pkg/providers/ is cosign's pluggable OIDC token source. The keyless signing flow needs a JWT to exchange with Fulcio for a code-signing certificate; this package abstracts where that JWT comes from so that the same cosign sign command works on a developer laptop, in GitHub Actions, in GitLab CI, on a SPIFFE-attested workload, etc.
The interface
// pkg/providers/interface.go
type Interface interface {
Enabled(ctx context.Context) bool
Provide(ctx context.Context, audience string) (string, error)
}
func Register(name string, p Interface)
func Enabled(ctx context.Context) bool
func Provide(ctx context.Context, audience string) (string, error)
func ProvideFrom(ctx context.Context, provider string) (Interface, error)Every concrete provider:
- Defines a
provider{}struct that implementsInterface. - Calls
providers.Register("name", &provider{})from aninit()function.
The orchestration in Provide(ctx, audience) walks the registered providers in registration order and uses the first one whose Enabled() returns true. If multiple are enabled, the last error from a Provide call is returned (or the first success). Registration happens at process start via blank imports — see the pkg/providers/all/ package.
Built-in providers
| Provider | Source dir | When Enabled() is true |
|---|---|---|
| GitHub Actions | pkg/providers/github/ |
ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN are set |
| GitLab CI | pkg/providers/gitlab/ |
running inside a GitLab job (env signals) |
| Buildkite | pkg/providers/buildkite/ |
the Buildkite agent OIDC env is set |
pkg/providers/google/ |
a Google service account is reachable | |
| SPIFFE | pkg/providers/spiffe/ |
SPIFFE_ENDPOINT_SOCKET is set |
| filesystem | pkg/providers/filesystem/ |
a token file path is set |
| envvar | pkg/providers/envvar/ |
SIGSTORE_ID_TOKEN is set |
| all | pkg/providers/all/ |
aggregator that imports the others |
The aggregator pkg/providers/all/ is what the CLI imports to pull every provider into the binary in one line.
How a cosign sign call uses it
sequenceDiagram
participant Sign as cosign sign
participant P as providers.Provide
participant GH as github provider
participant Env as envvar provider
participant Fulcio
Sign->>P: Provide(ctx, "sigstore")
P->>GH: Enabled?
GH-->>P: yes (in Actions)
P->>GH: Provide(ctx, "sigstore")
GH->>GH: HTTP GET ACTIONS_ID_TOKEN_REQUEST_URL with audience
GH-->>P: JWT
P-->>Sign: JWT
Sign->>Fulcio: CSR + JWT
Fulcio-->>Sign: leaf certificateIf no provider is enabled (the laptop case), cosign sign falls back to the interactive browser-based OAuth flow — that path lives in sigstore/sigstore rather than this package.
Why this design
- It lets cosign be a single static binary that "just works" across many CI systems without runtime config.
- It makes the CI integrations themselves trivial — each provider is ~50 lines of HTTP plus ambient-env detection.
- Adding a new provider is purely additive: write a package, register from
init(), add the blank import topkg/providers/all/.
Cross-references
- Keyless signing flow: Architecture / signing flow.
- Environment variables that affect provider selection: see the table in Getting started and the registry in
pkg/cosign/env/env.go.
Key source files
| File | Purpose |
|---|---|
pkg/providers/interface.go |
Interface, Register, Provide, ProvideFrom |
pkg/providers/all/ |
Aggregator imports |
pkg/providers/github/ |
GitHub Actions provider |
pkg/providers/gitlab/ |
GitLab CI provider |
pkg/providers/buildkite/ |
Buildkite agent provider |
pkg/providers/google/ |
GCP service account provider |
pkg/providers/spiffe/ |
SPIFFE workload API provider |
pkg/providers/filesystem/ |
File-backed token provider |
pkg/providers/envvar/ |
SIGSTORE_ID_TOKEN provider |
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.