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
11 changes: 4 additions & 7 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
with:
# go.mod's directive, not 'stable': golangci-lint is pinned below
# v2.13.0 (see the version comment further down), and that older
# (see the version comment further down), and the pinned
# release's bundled type-checker cannot parse the newer Go
# toolchain's stdlib (e.g. a generic-method signature in
# math/rand/v2 under Go 1.27), so linting must run on the Go
Expand All @@ -45,12 +45,9 @@ jobs:
${{ runner.os }}-go-build-

- name: Run golangci-lint
uses: golangci/golangci-lint-action@82606bf257cbaff209d206a39f5134f0cfbfd2ee # v9.2.1
uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9.3.0
with:
# Pin to a known-good release: v2.13.0 bundles honnef.co/go/tools
# v0.8.0-rc.1, whose nilness analyzer panics ("unhandled builtin
# recover") analyzing github.com/getsentry/sentry-go. Unpin once
# upstream ships a fixed release.
version: v2.12.2
# Pin to a known-good release so lint behavior is reproducible.
version: v2.13.2
# Enable golangci-lint's built-in caching (removes skip-cache: true)
args: --timeout=5m
1 change: 1 addition & 0 deletions cmd/thv-operator/controllers/mcpgroup_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ func (r *MCPGroupReconciler) handleDeletion(ctx context.Context, mcpGroup *mcpv1
if err := r.Update(ctx, mcpGroup); err != nil {
if errors.IsConflict(err) {
// Requeue to retry with fresh data
//nolint:staticcheck // Requeue preserves the controller's rate-limited conflict retry behavior.
return ctrl.Result{Requeue: true}, nil
}
ctxLogger.Error(err, "Failed to remove finalizer")
Expand Down
2 changes: 2 additions & 0 deletions cmd/thv-operator/controllers/mcpremoteproxy_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,7 @@ func (r *MCPRemoteProxyReconciler) ensureDeployment(
ctxLogger.Error(err, "Failed to update Deployment")
return ctrl.Result{}, err
}
//nolint:staticcheck // Requeue preserves the controller's existing rate-limited update behavior.
return ctrl.Result{Requeue: true}, nil
}

Expand Down Expand Up @@ -608,6 +609,7 @@ func (r *MCPRemoteProxyReconciler) ensureService(
ctxLogger.Error(err, "Failed to update Service")
return ctrl.Result{}, err
}
//nolint:staticcheck // Requeue preserves the controller's existing rate-limited update behavior.
return ctrl.Result{Requeue: true}, nil
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -939,7 +939,8 @@ func TestMCPRemoteProxy_ValidateAuthzPrimaryUpstreamProviderIgnored(t *testing.T
authzConfig: &mcpv1beta1.AuthzConfigRef{
Type: mcpv1beta1.AuthzConfigTypeInline,
Inline: &mcpv1beta1.InlineAuthzConfig{
Policies: []string{`permit(principal, action, resource);`},
Policies: []string{`permit(principal, action, resource);`},
//nolint:staticcheck // Exercises backward compatibility for the deprecated field.
PrimaryUpstreamProvider: "okta",
},
},
Expand Down
3 changes: 2 additions & 1 deletion cmd/thv-operator/controllers/mcpserver_authz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,8 @@ func TestValidateAuthzPrimaryUpstreamProviderIgnored(t *testing.T) {
authzConfig: &mcpv1beta1.AuthzConfigRef{
Type: mcpv1beta1.AuthzConfigTypeInline,
Inline: &mcpv1beta1.InlineAuthzConfig{
Policies: []string{`permit(principal, action, resource);`},
Policies: []string{`permit(principal, action, resource);`},
//nolint:staticcheck // Exercises the advisory emitted for the deprecated field.
PrimaryUpstreamProvider: "okta",
},
},
Expand Down
6 changes: 6 additions & 0 deletions cmd/thv-operator/controllers/mcpserver_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ func (r *MCPServerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
return ctrl.Result{}, err
} else if shouldTriggerRestart {
// Return and requeue to avoid double-processing after triggering restart
//nolint:staticcheck // Requeue preserves the controller's existing rate-limited update behavior.
return ctrl.Result{Requeue: true}, nil
}

Expand Down Expand Up @@ -513,6 +514,7 @@ func (r *MCPServerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
return ctrl.Result{}, err
}
// Deployment created successfully - return and requeue
//nolint:staticcheck // Requeue preserves the controller's existing rate-limited update behavior.
return ctrl.Result{Requeue: true}, nil
} else if err != nil {
ctxLogger.Error(err, "Failed to get Deployment")
Expand All @@ -533,6 +535,7 @@ func (r *MCPServerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
return ctrl.Result{}, err
}
// Spec updated - return and requeue
//nolint:staticcheck // Requeue preserves the controller's existing rate-limited update behavior.
return ctrl.Result{Requeue: true}, nil
}

Expand All @@ -554,6 +557,7 @@ func (r *MCPServerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
return ctrl.Result{}, err
}
// Service created successfully - return and requeue
//nolint:staticcheck // Requeue preserves the controller's existing rate-limited create behavior.
return ctrl.Result{Requeue: true}, nil
} else if err != nil {
ctxLogger.Error(err, "Failed to get Service")
Expand Down Expand Up @@ -612,6 +616,7 @@ func (r *MCPServerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
return ctrl.Result{}, err
}
// Spec updated - return and requeue
//nolint:staticcheck // Requeue preserves the controller's existing rate-limited update behavior.
return ctrl.Result{Requeue: true}, nil
}

Expand All @@ -632,6 +637,7 @@ func (r *MCPServerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
return ctrl.Result{}, err
}
// Spec updated - return and requeue
//nolint:staticcheck // Requeue preserves the controller's existing rate-limited update behavior.
return ctrl.Result{Requeue: true}, nil
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3530,7 +3530,8 @@ func TestVirtualMCPServerValidateAuthzUpstreamAvailable(t *testing.T) {
return &mcpv1beta1.AuthzConfigRef{
Type: "inline",
Inline: &mcpv1beta1.InlineAuthzConfig{
Policies: []string{`permit(principal, action, resource);`},
Policies: []string{`permit(principal, action, resource);`},
//nolint:staticcheck // Exercises backward compatibility for the deprecated field.
PrimaryUpstreamProvider: primary,
},
}
Expand Down Expand Up @@ -3829,7 +3830,8 @@ func TestVirtualMCPServerValidateAuthzUpstreamAvailable_DeprecationEvent(t *test
inlineAuthzRefWithDeprecatedPrimary := &mcpv1beta1.AuthzConfigRef{
Type: "inline",
Inline: &mcpv1beta1.InlineAuthzConfig{
Policies: []string{`permit(principal, action, resource);`},
Policies: []string{`permit(principal, action, resource);`},
//nolint:staticcheck // Exercises backward compatibility for the deprecated field.
PrimaryUpstreamProvider: "okta",
},
}
Expand Down
9 changes: 6 additions & 3 deletions cmd/thv-operator/pkg/vmcpconfig/converter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2127,7 +2127,8 @@ func TestConvertIncomingAuth_PrimaryUpstreamProvider(t *testing.T) {
authzConfig: &mcpv1beta1.AuthzConfigRef{
Type: "inline",
Inline: &mcpv1beta1.InlineAuthzConfig{
Policies: []string{`permit(principal, action, resource);`},
Policies: []string{`permit(principal, action, resource);`},
//nolint:staticcheck // Exercises conversion of the deprecated field.
PrimaryUpstreamProvider: "okta",
},
},
Expand Down Expand Up @@ -2162,7 +2163,8 @@ func TestConvertIncomingAuth_PrimaryUpstreamProvider(t *testing.T) {
authzConfig: &mcpv1beta1.AuthzConfigRef{
Type: "inline",
Inline: &mcpv1beta1.InlineAuthzConfig{
Policies: []string{`permit(principal, action, resource);`},
Policies: []string{`permit(principal, action, resource);`},
//nolint:staticcheck // Exercises conversion of the deprecated field.
PrimaryUpstreamProvider: "github",
},
},
Expand All @@ -2182,7 +2184,8 @@ func TestConvertIncomingAuth_PrimaryUpstreamProvider(t *testing.T) {
authzConfig: &mcpv1beta1.AuthzConfigRef{
Type: "inline",
Inline: &mcpv1beta1.InlineAuthzConfig{
Policies: []string{`permit(principal, action, resource);`},
Policies: []string{`permit(principal, action, resource);`},
//nolint:staticcheck // Exercises conversion of the deprecated field.
PrimaryUpstreamProvider: "okta",
},
},
Expand Down
5 changes: 4 additions & 1 deletion cmd/thv/app/llm.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,10 @@ func oidcLogin(ctx context.Context, cfg *llm.Config, skipBrowser bool) error {
if err != nil {
return fmt.Errorf("building token source: %w", err)
}
_, err = ts.Token(ctx)
token, err := ts.Token(ctx)
if err == nil {
cfg.SetDiscoveryAccessToken(token)
}
return err
}

Expand Down
26 changes: 13 additions & 13 deletions pkg/authserver/spiffe_trust_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,19 +86,19 @@ func TestValidateSPIFFETrust(t *testing.T) {

valid := func() ([]SPIFFETrustDomainRunConfig, *InboundGrantsRunConfig) {
return []SPIFFETrustDomainRunConfig{{
Name: "production",
TrustDomain: "example.org",
Methods: []SPIFFEAuthenticationMethod{SPIFFEAuthenticationMethodX509, SPIFFEAuthenticationMethodJWT},
BundleSource: validWorkloadAPIBundleSource(),
}}, &InboundGrantsRunConfig{SPIFFEClientAuth: []SPIFFEClientAuthRunConfig{{
TrustDomainRef: "production",
PrincipalPattern: "spiffe://example.org/ns/default/*",
ClientID: "agent-client",
Methods: []SPIFFEAuthenticationMethod{SPIFFEAuthenticationMethodX509},
Audiences: []string{"https://mcp.example.org/resource"},
Scopes: []string{"openid"},
GrantTypes: []string{SPIFFEGrantTypeTokenExchange},
}}}
Name: "production",
TrustDomain: "example.org",
Methods: []SPIFFEAuthenticationMethod{SPIFFEAuthenticationMethodX509, SPIFFEAuthenticationMethodJWT},
BundleSource: validWorkloadAPIBundleSource(),
}}, &InboundGrantsRunConfig{SPIFFEClientAuth: []SPIFFEClientAuthRunConfig{{
TrustDomainRef: "production",
PrincipalPattern: "spiffe://example.org/ns/default/*",
ClientID: "agent-client",
Methods: []SPIFFEAuthenticationMethod{SPIFFEAuthenticationMethodX509},
Audiences: []string{"https://mcp.example.org/resource"},
Scopes: []string{"openid"},
GrantTypes: []string{SPIFFEGrantTypeTokenExchange},
}}}
}

tests := []struct {
Expand Down
20 changes: 6 additions & 14 deletions pkg/client/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -425,19 +425,15 @@ var supportedClientIntegrations = []clientAppConfig{
SupportsSkills: true,
SkillsGlobalPath: []string{".copilot", skillsDirName},
SkillsProjectPath: []string{".github", skillsDirName},
// LLM gateway: patches settings.json (same dir as mcp.json, different file)
LLMGatewayMode: llmgateway.ModeProxy,
LLMSettingsFile: "settings.json",
// VS Code reads custom LLM provider groups from chatLanguageModels.json.
LLMGatewayMode: llmgateway.ModeVSCode,
LLMSettingsFile: "chatLanguageModels.json",
LLMSettingsRelPath: []string{"Code - Insiders", "User"},
LLMSettingsPlatformPrefix: map[Platform][]string{
PlatformLinux: {".config"},
PlatformDarwin: {"Library", "Application Support"},
PlatformWindows: {"AppData", "Roaming"},
},
LLMGatewayKeys: []LLMGatewayKeySpec{
{JSONPointer: "/github.copilot.advanced.serverUrl", ValueField: "ProxyBaseURL"},
{JSONPointer: "/github.copilot.advanced.apiKey", ValueField: "PlaceholderAPIKey"},
},
},
{
ClientType: VSCode,
Expand Down Expand Up @@ -467,19 +463,15 @@ var supportedClientIntegrations = []clientAppConfig{
SupportsSkills: true,
SkillsGlobalPath: []string{".copilot", skillsDirName},
SkillsProjectPath: []string{".github", skillsDirName},
// LLM gateway: patches settings.json (same dir as mcp.json, different file)
LLMGatewayMode: llmgateway.ModeProxy,
LLMSettingsFile: "settings.json",
// VS Code reads custom LLM provider groups from chatLanguageModels.json.
LLMGatewayMode: llmgateway.ModeVSCode,
LLMSettingsFile: "chatLanguageModels.json",
LLMSettingsRelPath: []string{"Code", "User"},
LLMSettingsPlatformPrefix: map[Platform][]string{
PlatformLinux: {".config"},
PlatformDarwin: {"Library", "Application Support"},
PlatformWindows: {"AppData", "Roaming"},
},
LLMGatewayKeys: []LLMGatewayKeySpec{
{JSONPointer: "/github.copilot.advanced.serverUrl", ValueField: "ProxyBaseURL"},
{JSONPointer: "/github.copilot.advanced.apiKey", ValueField: "PlaceholderAPIKey"},
},
},
{
ClientType: Cursor,
Expand Down
6 changes: 6 additions & 0 deletions pkg/client/llm_gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ func (cm *ClientManager) ConfigureLLMGateway(clientType ClientApp, cfg llmgatewa
if appCfg.LLMGatewayMode == llmgateway.ModeCodexAuth {
return cm.configureCodexAuth(appCfg, cfg)
}
if appCfg.LLMGatewayMode == llmgateway.ModeVSCode {
return cm.configureVSCode(appCfg, cfg)
}

path := cm.buildLLMSettingsPath(appCfg)

Expand Down Expand Up @@ -188,6 +191,9 @@ func (cm *ClientManager) RevertLLMGateway(clientType ClientApp, configPath strin
if appCfg.LLMGatewayMode == llmgateway.ModeCodexAuth {
return cm.revertCodexAuth(appCfg, configPath)
}
if appCfg.LLMGatewayMode == llmgateway.ModeVSCode {
return cm.revertVSCode(appCfg, configPath)
}

return revertJSONPointerGateway(appCfg, configPath)
}
Expand Down
Loading
Loading