Documentation
¶
Overview ¶
Package credsource is the inference-plane credential-source seam: it answers WHERE a runtime's LLM PROVIDER API KEY comes from — the process environment (boot config, the historical default) or a coordinator-served broker the runtime PULLS from at connect + refresh.
A DISTINCT seam, deliberately (not a §13 parallel implementation) ¶
This seam follows the §4.4 seam PATTERN but is NOT the OAuth-plane `internal/tools/auth/credsource.Source`. The two resolve different credentials for different consumers with different custody models:
- The OAuth seam resolves an OAuth provider's own client_id / client_secret for the tool-plane token-exchange driver, with a PER-IDENTITY, LAZY pull (a tool bearer is identity-scoped).
- This seam resolves an LLM provider API KEY for the bifrost `Account`, with a RUNTIME-SCOPED connect + refresh pull (a provider key is a runtime-level credential, never identity-scoped data — it does not widen the isolation tuple).
Folding both into one driver would leak the per-identity assumptions the OAuth seam bakes in onto the runtime-scoped path; the sibling is justified, not incidental. The two MAY share the HTTP-pull mechanics (this file keeps them credential-agnostic and self-contained), but the interface and its custody model are distinct.
Connect + refresh only — never a per-call KEK decrypt ¶
The pulled key is cached in memory and rides the existing atomic key-swap (llm.LiveKey): the bifrost `Account.GetKeysForProvider` reads the live atomic pointer on the inference HOT PATH with no broker round-trip and no per-call decrypt. A broker-side rotation lands on the next call via InferenceKeySource.Refresh, with no `ReloadConfig` race.
Fail loud, no dual path, no stale cache ¶
A broker unreachable at connect OR a failed refresh raises the typed ErrProviderKeyUnavailable. The runtime NEVER falls back to a local / boot key, and NEVER serves a stale cached key past its refresh contract: once the cache TTL is crossed with no successful refresh, the live key is zeroed so bound calls fail closed rather than serve a possibly-revoked key. A provider is brokered XOR local, config-declared (validated loud at boot). Nothing is persisted — the coordinator remains sole custodian.
Index ¶
Constants ¶
const ( // RuntimePrincipalTenant is the reserved tenant component of the // runtime service-principal scope. RuntimePrincipalTenant = "_harbor_runtime" // RuntimePrincipalUser is the reserved user component of the runtime // service-principal scope. RuntimePrincipalUser = "_service_principal" )
Reserved runtime-scope identity components. A runtime-scoped credential pull fires outside any (tenant, user, session) request, but the event bus requires a structural triple on every published Event. These reserved components satisfy that transport requirement WITHOUT synthesizing a real user's session: they are infrastructure identity, never an isolation principal, and storage / memory / event-filter scoping never treats them as one (they do not widen the isolation tuple, §4). The authoritative audit attribution is the payload's RuntimePrincipal, not this triple.
Variables ¶
ErrProviderKeyUnavailable — the broker was unreachable at connect OR a refresh failed. The runtime NEVER falls back to a local key and NEVER serves a stale cached key past its refresh contract. Callers compare via errors.Is.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
// Provider is the LLM provider the key authenticates (e.g. "openai").
Provider string
// BrokerName is the boot-declared inference-broker name (non-secret,
// audit + error attribution).
BrokerName string
// RuntimePrincipal is the per-runtime service-principal id the pull
// audit event is attributed to. Non-secret. Falls back to AuthTokenEnv
// (the env var NAME, still non-secret) when empty.
RuntimePrincipal string
// CredentialURL is the boot-pinned coordinator pull endpoint.
CredentialURL string
// AuthTokenEnv names the env var holding the runtime's own broker
// credential (the Bearer presented to CredentialURL).
AuthTokenEnv string
// CacheTTL caps the in-memory serve horizon (0 = default 5m).
CacheTTL time.Duration
// Timeout bounds a single pull (0 = default 30s).
Timeout time.Duration
// Live is the atomic key holder the bifrost Account reads. Required.
Live *llm.LiveKey
// Bus + Redactor are mandatory — every pull emits a runtime-scoped
// audit event through them, and a pull that cannot be audited fails loud.
Bus events.EventBus
Redactor audit.Redactor
// Clock overrides the time source (tests). Nil = time.Now.
Clock func() time.Time
// HTTPClient overrides the fetch client (tests). Nil = a fresh client
// with the resolved timeout. A caller-supplied client is shallow-copied
// so its CheckRedirect is set without mutating the caller's instance.
HTTPClient *http.Client
}
Config is the constructor input for an InferenceKeySource. The endpoint / audience / scope ceiling come from the boot-declared broker (never the wire); the Live holder is the SAME atomic key the bifrost Account reads, so a pull lands on the next hot-path read with no ReloadConfig.
type InferenceKeySource ¶
type InferenceKeySource struct {
// contains filtered or unexported fields
}
InferenceKeySource pulls a provider key from a boot-declared broker at connect + refresh, caches it in memory (TTL-capped, single-flighted), and seeds / refreshes the LiveKey the bifrost Account reads. Immutable after construction; safe to share across N goroutines. It NEVER decrypts on the per-call hot path — the hot path reads the live atomic pointer.
func NewInferenceKeySource ¶
func NewInferenceKeySource(cfg Config) (*InferenceKeySource, error)
NewInferenceKeySource constructs the source. It validates the block SHAPE (endpoint well-formed https / loopback, auth-token env named, Live / Bus / Redactor present) but does NOT fetch — the pull happens at Connect.
func (*InferenceKeySource) Close ¶
func (s *InferenceKeySource) Close()
Close closes the binding: the live key is zeroed so a subsequently bound call fails loud rather than serving the old key (the provider-SET uninstall contract — never a silent no-op serving the old key). The backstop timer is stopped. A running Run scheduler is stopped separately by cancelling its ctx.
func (*InferenceKeySource) Connect ¶
func (s *InferenceKeySource) Connect(ctx context.Context) error
Connect performs the first authenticated pull and seeds the live key. Fails loud with ErrProviderKeyUnavailable on broker-unreachable — the caller (boot wiring) exits non-zero naming the broker + missing config.
func (*InferenceKeySource) Refresh ¶
func (s *InferenceKeySource) Refresh(ctx context.Context) error
Refresh re-pulls on the TTL boundary and atomically swaps the live key. A failed refresh raises ErrProviderKeyUnavailable; once the cache TTL is crossed with no successful refresh the live key is zeroed rather than served stale (a broker-side revocation that fails to propagate surfaces).
func (*InferenceKeySource) Run ¶
func (s *InferenceKeySource) Run(ctx context.Context)
Run drives the refresh cadence off the broker's expiry: it re-pulls s.refreshLead ahead of the serve horizon so a fresh key is seeded before the current one expires. It is ctx-cancellable and returns when ctx is done (join it on shutdown). A refresh failure is non-fatal to the loop — onFetchFailed already drops a stale key past its horizon and the pull re-emits its audit event; the loop retries on the next tick. Call Connect once before Run so the first key is seeded synchronously (a boot-fail-loud point); Run keeps it fresh thereafter.
type KeySource ¶
type KeySource interface {
// Connect performs the first authenticated pull and seeds the LiveKey.
// Fails loud with ErrProviderKeyUnavailable on broker-unreachable.
Connect(ctx context.Context) error
// Refresh re-pulls on the TTL boundary and atomically swaps the LiveKey.
// A failed refresh raises ErrProviderKeyUnavailable; once the cache TTL
// is crossed with no success the live key is zeroed rather than served
// stale.
Refresh(ctx context.Context) error
// Close closes the binding: the live key is zeroed so a subsequently
// bound call fails loud rather than serving the old key.
Close()
}
KeySource is the §4.4-pattern seam interface an inference-plane credential source implements. It is a MANDATORY interface (no optional-capability ceremony): the source pulls the provider key at connect + refresh, seeds / refreshes the llm.LiveKey the bifrost `Account` reads, and closes the binding on uninstall.
Concurrent reuse: a KeySource is a compiled artifact built once and shared across N goroutines. It holds immutable configuration plus an internally-synchronised in-memory cache; the inference hot path reads the LiveKey atomic pointer, never the source.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package inferencebrokertest ships the committed REFERENCE implementation of the inference-plane credential-pull contract: an httptest server that serves an LLM provider's API key to the broker-pull [InferenceKeySource].
|
Package inferencebrokertest ships the committed REFERENCE implementation of the inference-plane credential-pull contract: an httptest server that serves an LLM provider's API key to the broker-pull [InferenceKeySource]. |