-
Notifications
You must be signed in to change notification settings - Fork 191
Description
Description
Add the foundational type definitions needed by all subsequent phases of RFC-0054. This phase introduces the StrategyTypeUpstreamInject constant, the UpstreamInjectConfig struct, the ErrUpstreamTokenNotFound sentinel error, and two new fields on existing structs (UpstreamInject on BackendAuthStrategy, SubjectProviderName on TokenExchangeConfig). The generated deep-copy file is also regenerated to reflect the new struct. No runtime behavior changes — all new fields are optional and zero-valued by default, so existing configurations are unaffected.
Context
This is Phase 1 of the RFC-0054 epic (#3925), which implements the upstream_inject outgoing auth strategy for vMCP. The strategy reads upstream IDP access tokens from identity.UpstreamTokens (populated by RFC-0052's auth middleware) and injects them as Authorization: Bearer headers on outgoing backend requests.
Phase 1 is the root task: it adds the shared type definitions that Phases 2, 3, and 4 all depend on. Phases 2 (strategy implementations), 3 (startup validation), and 4 (CRD and converter) cannot start until these types are merged. Phase 4 in particular can be parallelized with Phases 2 and 3 immediately after Phase 1 lands, since it only depends on the types package — not on RFC-0052 or RFC-0053.
Dependencies: None (root task)
Blocks: TASK-002 (Phase 2: Strategy implementations), TASK-003 (Phase 3: Startup validation), TASK-004 (Phase 4: CRD and converter)
Acceptance Criteria
-
StrategyTypeUpstreamInject = "upstream_inject"constant is present inpkg/vmcp/auth/types/types.goalongside the otherStrategyType*constants -
UpstreamInjectConfigstruct is present with a singleProviderName stringfield, taggedjson:"providerName" yaml:"providerName", and carries both// +kubebuilder:object:generate=trueand// +gendocmarkers -
ErrUpstreamTokenNotFoundsentinel variable is present:var ErrUpstreamTokenNotFound = errors.New("upstream token not found") -
BackendAuthStrategystruct has a new field:UpstreamInject *UpstreamInjectConfig \json:"upstreamInject,omitempty" yaml:"upstreamInject,omitempty"`` -
TokenExchangeConfigstruct has a new field:SubjectProviderName string \json:"subjectProviderName,omitempty" yaml:"subjectProviderName,omitempty"`` -
pkg/vmcp/auth/types/zz_generated.deepcopy.gois regenerated (viatask gen) and includesDeepCopyInto/DeepCopyforUpstreamInjectConfigand the nil-check pointer copy for the newUpstreamInjectfield onBackendAuthStrategy - All existing unit tests continue to pass (
task test) - SPDX license header is present on all modified Go files (
task license-check)
Technical Approach
Recommended Implementation
All changes in this phase are confined to pkg/vmcp/auth/types/types.go. The file is a leaf package with no dependencies on other pkg/vmcp/* packages — keep it that way; no new imports are needed beyond the standard errors package for the sentinel.
Add items in the following order to maintain the file's current organization (constants, then structs):
- Append
StrategyTypeUpstreamInjectto the existingconstblock - Add the
UpstreamInjectConfigstruct afterTokenExchangeConfigwith both codegen markers - Add
ErrUpstreamTokenNotFoundas a package-levelvarafter theconstblock - Add
UpstreamInject *UpstreamInjectConfigtoBackendAuthStrategyafter the existingTokenExchangefield - Add
SubjectProviderName stringtoTokenExchangeConfigafter the existingSubjectTokenTypefield (last field,omitempty)
After editing, run task gen to regenerate zz_generated.deepcopy.go. The generated output will include:
- A new
DeepCopyInto/DeepCopypair forUpstreamInjectConfig(trivial*out = *insince it has only scalar fields) - A nil-check pointer copy block for
BackendAuthStrategy.UpstreamInjectinBackendAuthStrategy.DeepCopyInto
Patterns & Frameworks
- Follow the existing pattern for strategy constants in the
constblock (seeStrategyTypeUnauthenticated,StrategyTypeHeaderInjection,StrategyTypeTokenExchange) - Follow the existing struct documentation style — Go doc comment explaining the type, then field-level comments explaining each field
UpstreamInjectConfigfollows the same shape asHeaderInjectionConfig(a typed config struct for a named strategy)- Sentinel errors follow
errors.New(...)with a descriptive lowercase message; they are checked viaerrors.Is()by callers — always wrap with%wat the call site soerrors.Is()works at any depth - Use
// +optionalannotation on the newSubjectProviderNamefield comment to signal the field is optional (consistent with operator API conventions)
Code Pointers
pkg/vmcp/auth/types/types.go— the only file with source code changes; all five additions land herepkg/vmcp/auth/types/zz_generated.deepcopy.go— regenerated artifact; do not edit manually; runtask genafter editingtypes.gopkg/vmcp/auth/strategies/unauthenticated.go— reference for how strategy constants and types are used; note howName()returns the constant directlypkg/vmcp/auth/strategies/tokenexchange.go— reference for howTokenExchangeConfigfields are used inparseTokenExchangeConfig; the newSubjectProviderNamefield will be consumed here in Phase 2pkg/vmcp/auth/factory/outgoing.go— reference for how strategy type constants are passed toRegisterStrategy; Phase 2 will add a new registration here using the constant defined in this phase
Component Interfaces
The following types and values must be present after this phase — downstream phases depend on them exactly as specified:
// New constant — added alongside existing StrategyType* constants
const StrategyTypeUpstreamInject = "upstream_inject"
// New sentinel error — checked with errors.Is() by callers
var ErrUpstreamTokenNotFound = errors.New("upstream token not found")
// New config struct — needs +kubebuilder:object:generate=true and +gendoc markers
// +kubebuilder:object:generate=true
// +gendoc
type UpstreamInjectConfig struct {
// ProviderName is the name of the upstream IDP provider whose access token
// should be injected as the Authorization: Bearer header on backend requests.
ProviderName string `json:"providerName" yaml:"providerName"`
}
// BackendAuthStrategy gains one field (all existing fields unchanged)
type BackendAuthStrategy struct {
Type string `json:"type" yaml:"type"`
HeaderInjection *HeaderInjectionConfig `json:"headerInjection,omitempty" yaml:"headerInjection,omitempty"`
TokenExchange *TokenExchangeConfig `json:"tokenExchange,omitempty" yaml:"tokenExchange,omitempty"`
// UpstreamInject contains configuration for the upstream inject auth strategy.
// Used when Type = "upstream_inject".
UpstreamInject *UpstreamInjectConfig `json:"upstreamInject,omitempty" yaml:"upstreamInject,omitempty"`
}
// TokenExchangeConfig gains one optional field (all existing fields unchanged)
type TokenExchangeConfig struct {
// ... existing fields unchanged ...
// SubjectProviderName is the upstream provider name whose token is used as the
// RFC 8693 subject token instead of identity.Token when performing token exchange.
// +optional
SubjectProviderName string `json:"subjectProviderName,omitempty" yaml:"subjectProviderName,omitempty"`
}Testing Strategy
No new test files are required for this phase. The acceptance criteria for testing are:
Compilation check
-
go build ./pkg/vmcp/auth/types/...succeeds with the new types present -
go vet ./pkg/vmcp/auth/types/...reports no issues
Existing regression tests
-
task testpasses without modification — no existing test should need updating since all new fields are additive and optional
Codegen verification
-
task gencompletes without errors -
zz_generated.deepcopy.gocontainsDeepCopyIntoandDeepCopyforUpstreamInjectConfig -
zz_generated.deepcopy.gocontains the nil-check pointer copy block forUpstreamInjectinBackendAuthStrategy.DeepCopyInto - The generated file is committed alongside the type changes
License check
-
task license-checkpasses (SPDX headers on all modified files)
Out of Scope
- Any runtime behavior changes — new fields are optional and must not alter behavior for configurations that omit them
- Implementation of
UpstreamInjectStrategy(Phase 2) - Startup validation rules V-01, V-02, V-06 (Phase 3)
- CRD type additions (
ExternalAuthTypeUpstreamInject,UpstreamInjectSpec) and converter (Phase 4) - Architecture documentation updates (
docs/arch/02-core-concepts.md,docs/vmcp-auth.md) - Step-up auth signaling (UC-06) —
ErrUpstreamTokenNotFoundis defined here but the intercept/redirect flow is a separate RFC - Actor token (
ActorProviderName) or any parallel field beyondSubjectProviderName
References
- RFC-0054 (primary):
docs/proposals/THV-0054-vmcp-upstream-inject-strategy.md - Parent epic: vMCP: implement upstream_inject outgoing auth strategy #3925
- RFC-0052 (multi-upstream IDP, defines
identity.UpstreamTokens): Auth Server: multi-upstream provider support #3924 - RFC-0053 (embedded AS in vMCP, prerequisite for Phase 3): vMCP: add embedded authorization server #4120