From 622a4c54a9e0a6a9dbcbca760d3da1599bcbee30 Mon Sep 17 00:00:00 2001 From: Samuel K Date: Thu, 6 Aug 2026 13:42:00 +0000 Subject: [PATCH 1/6] fix(lint): resolve staticcheck SA1019 findings Migrated k8s.io/apimachinery/pkg/util/httpstream to its k8s.io/streaming replacement (drop-in, already an indirect dependency) and httputil.ReverseProxy.Director to .Rewrite in pkg/ts/workspace_server.go's three reverse proxies, preserving exact prior behavior including the implicit X-Forwarded-For header Director set automatically. Suppressed the remaining findings where migration is out of scope for a lint-cleanup PR: the MCP SDK's session.Log (SEP-2577 protocol-level deprecation, no replacement API in go-sdk v1.7.0) and the three inject.ExecFunc/inject.Inject call sites in pkg/agent/inject.go, which are part of the legacy shell injection path retained until callers migrate to AgentDelivery. --- cmd/mcp/notify.go | 1 + go.mod | 2 +- pkg/agent/inject.go | 4 +- pkg/driver/kubernetes/client.go | 2 +- pkg/ts/workspace_server.go | 78 +++++++++++++++++++++++---------- 5 files changed, 60 insertions(+), 27 deletions(-) diff --git a/cmd/mcp/notify.go b/cmd/mcp/notify.go index e65d765f5..77c16f100 100644 --- a/cmd/mcp/notify.go +++ b/cmd/mcp/notify.go @@ -36,6 +36,7 @@ func streamLogsToSession( if line == "" { continue } + //nolint:staticcheck // SA1019: MCP logging capability deprecated per SEP-2577 but functional through its 12-month deprecation window; no replacement API exists in go-sdk v1.7.0. _ = session.Log(ctx, &sdkmcp.LoggingMessageParams{ Level: "info", Logger: "devsy", diff --git a/go.mod b/go.mod index e83b6038f..e9139c480 100644 --- a/go.mod +++ b/go.mod @@ -77,6 +77,7 @@ require ( k8s.io/klog/v2 v2.140.0 k8s.io/kube-aggregator v0.36.3 k8s.io/kubectl v0.36.3 + k8s.io/streaming v0.36.3 k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3 mvdan.cc/sh/v3 v3.13.1 sigs.k8s.io/controller-runtime v0.24.1 @@ -319,7 +320,6 @@ require ( k8s.io/component-base v0.36.3 // indirect k8s.io/kube-openapi v0.0.0-20260624041617-8f3fa4921821 // indirect k8s.io/metrics v0.36.3 // indirect - k8s.io/streaming v0.36.3 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect diff --git a/pkg/agent/inject.go b/pkg/agent/inject.go index 667a976d5..6da48dabc 100644 --- a/pkg/agent/inject.go +++ b/pkg/agent/inject.go @@ -38,6 +38,7 @@ type InjectOptions struct { // Ctx is the context for the injection operation. Required. Ctx context.Context // Exec is the function used to execute commands on the remote machine. Required. + //nolint:staticcheck // SA1019: legacy shell injection path, retained until callers migrate to AgentDelivery Exec inject.ExecFunc // IsLocal indicates if the injection target is the local machine. @@ -228,6 +229,7 @@ func injectAgent(ctx *injectContext) error { binaryLoader := createBinaryLoader(ctx) scriptParams := buildScriptParams(ctx) + //nolint:staticcheck // SA1019: legacy shell injection path, retained until callers migrate to AgentDelivery wasExecuted, err := inject.Inject(inject.InjectOptions{ Ctx: opts.Ctx, Exec: opts.Exec, @@ -354,7 +356,7 @@ func (vc *versionChecker) buildExistsCheck(agentPath string) string { func (vc *versionChecker) detectRemoteAgentVersion( ctx context.Context, - exec inject.ExecFunc, + exec inject.ExecFunc, //nolint:staticcheck // SA1019: legacy shell injection path, retained until callers migrate to AgentDelivery agentPath string, ) (string, error) { buf := &bytes.Buffer{} diff --git a/pkg/driver/kubernetes/client.go b/pkg/driver/kubernetes/client.go index 904e8c236..64b311fa4 100644 --- a/pkg/driver/kubernetes/client.go +++ b/pkg/driver/kubernetes/client.go @@ -8,12 +8,12 @@ import ( "os" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/util/httpstream" "k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/remotecommand" + "k8s.io/streaming/pkg/httpstream" ) type Client struct { diff --git a/pkg/ts/workspace_server.go b/pkg/ts/workspace_server.go index 469c8826b..0ece8b447 100644 --- a/pkg/ts/workspace_server.go +++ b/pkg/ts/workspace_server.go @@ -326,13 +326,17 @@ func (s *WorkspaceServer) gitCredentialsHandler( return } - // Build the reverse proxy with a custom Director. - proxy := httputil.NewSingleHostReverseProxy(parsedURL) - proxy.Director = func(req *http.Request) { - dest := *parsedURL - req.URL = &dest - req.Host = dest.Host - req.Header.Set("Authorization", "Bearer "+s.config.AccessKey) + // Build the reverse proxy with Rewrite (Director is deprecated); dest is + // forced to parsedURL rather than joined with the inbound path, matching + // the previous Director's behavior. + proxy := &httputil.ReverseProxy{ + Rewrite: func(pr *httputil.ProxyRequest) { + dest := *parsedURL + pr.Out.URL = &dest + pr.Out.Host = dest.Host + pr.Out.Header.Set("Authorization", "Bearer "+s.config.AccessKey) + addForwardedFor(pr) + }, } proxy.Transport = transport proxy.ServeHTTP(w, r) @@ -368,13 +372,17 @@ func (s *WorkspaceServer) dockerCredentialsHandler( return } - // Build the reverse proxy with a custom Director. - proxy := httputil.NewSingleHostReverseProxy(parsedURL) - proxy.Director = func(req *http.Request) { - dest := *parsedURL - req.URL = &dest - req.Host = dest.Host - req.Header.Set("Authorization", "Bearer "+s.config.AccessKey) + // Build the reverse proxy with Rewrite (Director is deprecated); dest is + // forced to parsedURL rather than joined with the inbound path, matching + // the previous Director's behavior. + proxy := &httputil.ReverseProxy{ + Rewrite: func(pr *httputil.ProxyRequest) { + dest := *parsedURL + pr.Out.URL = &dest + pr.Out.Host = dest.Host + pr.Out.Header.Set("Authorization", "Bearer "+s.config.AccessKey) + addForwardedFor(pr) + }, } proxy.Transport = transport proxy.ServeHTTP(w, r) @@ -411,16 +419,20 @@ func (s *WorkspaceServer) httpPortForwardHandler(w http.ResponseWriter, r *http. parsedURL.Host = "127.0.0.1:" + targetPort log.Debugf("httpPortForwardHandler: final target URL=%s", parsedURL.String()) - // Build the reverse proxy with a custom Director. - proxy := httputil.NewSingleHostReverseProxy(parsedURL) - proxy.Director = func(req *http.Request) { - dest := *parsedURL - req.URL = &dest - req.Host = dest.Host - // Remove custom headers so they are not forwarded. - req.Header.Del("X-Loft-Forward-Port") - req.Header.Del("X-Loft-Forward-Url") - req.Header.Del("X-Loft-Forward-Authorization") + // Build the reverse proxy with Rewrite (Director is deprecated); dest is + // forced to parsedURL rather than joined with the inbound path, matching + // the previous Director's behavior. + proxy := &httputil.ReverseProxy{ + Rewrite: func(pr *httputil.ProxyRequest) { + dest := *parsedURL + pr.Out.URL = &dest + pr.Out.Host = dest.Host + // Remove custom headers so they are not forwarded. + pr.Out.Header.Del("X-Loft-Forward-Port") + pr.Out.Header.Del("X-Loft-Forward-Url") + pr.Out.Header.Del("X-Loft-Forward-Authorization") + addForwardedFor(pr) + }, } proxy.Transport = http.DefaultTransport @@ -432,6 +444,24 @@ func (s *WorkspaceServer) httpPortForwardHandler(w http.ResponseWriter, r *http. proxy.ServeHTTP(w, r) } +// addForwardedFor sets X-Forwarded-For on the outbound proxy request, +// replicating the behavior ReverseProxy applies automatically when using +// the deprecated Director field but not when using Rewrite. +func addForwardedFor(pr *httputil.ProxyRequest) { + clientIP, _, err := net.SplitHostPort(pr.In.RemoteAddr) + if err != nil { + return + } + prior, ok := pr.Out.Header["X-Forwarded-For"] + omit := ok && prior == nil + if len(prior) > 0 { + clientIP = strings.Join(prior, ", ") + ", " + clientIP + } + if !omit { + pr.Out.Header.Set("X-Forwarded-For", clientIP) + } +} + // handleSSHConnections continuously accepts SSH connections and handles each one. func (s *WorkspaceServer) handleSSHConnections(ctx context.Context, listener net.Listener) { for { From d0646aec3a093d14c8b1aaacebe89b1f0dfc7576 Mon Sep 17 00:00:00 2001 From: Samuel K Date: Thu, 6 Aug 2026 13:50:41 +0000 Subject: [PATCH 2/6] fix(lint): shorten nolint reason comments to satisfy lll --- cmd/mcp/notify.go | 2 +- pkg/agent/inject.go | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/mcp/notify.go b/cmd/mcp/notify.go index 77c16f100..cad10a690 100644 --- a/cmd/mcp/notify.go +++ b/cmd/mcp/notify.go @@ -36,7 +36,7 @@ func streamLogsToSession( if line == "" { continue } - //nolint:staticcheck // SA1019: MCP logging capability deprecated per SEP-2577 but functional through its 12-month deprecation window; no replacement API exists in go-sdk v1.7.0. + //nolint:staticcheck // SA1019: deprecated per SEP-2577; no replacement in go-sdk v1.7.0 _ = session.Log(ctx, &sdkmcp.LoggingMessageParams{ Level: "info", Logger: "devsy", diff --git a/pkg/agent/inject.go b/pkg/agent/inject.go index 6da48dabc..60bed5dc3 100644 --- a/pkg/agent/inject.go +++ b/pkg/agent/inject.go @@ -354,9 +354,10 @@ func (vc *versionChecker) buildExistsCheck(agentPath string) string { agentPath, agentPath, vc.remoteVersion) } +//nolint:staticcheck // SA1019: legacy shell injection path, retained until callers migrate func (vc *versionChecker) detectRemoteAgentVersion( ctx context.Context, - exec inject.ExecFunc, //nolint:staticcheck // SA1019: legacy shell injection path, retained until callers migrate to AgentDelivery + exec inject.ExecFunc, agentPath string, ) (string, error) { buf := &bytes.Buffer{} From 91300a2084c1857b281e0db09d0e4d42ff1fc4a8 Mon Sep 17 00:00:00 2001 From: Samuel K Date: Thu, 6 Aug 2026 18:57:43 -0500 Subject: [PATCH 3/6] style: update comments --- pkg/ts/workspace_server.go | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/pkg/ts/workspace_server.go b/pkg/ts/workspace_server.go index 0ece8b447..3a26ed955 100644 --- a/pkg/ts/workspace_server.go +++ b/pkg/ts/workspace_server.go @@ -326,9 +326,6 @@ func (s *WorkspaceServer) gitCredentialsHandler( return } - // Build the reverse proxy with Rewrite (Director is deprecated); dest is - // forced to parsedURL rather than joined with the inbound path, matching - // the previous Director's behavior. proxy := &httputil.ReverseProxy{ Rewrite: func(pr *httputil.ProxyRequest) { dest := *parsedURL @@ -372,9 +369,6 @@ func (s *WorkspaceServer) dockerCredentialsHandler( return } - // Build the reverse proxy with Rewrite (Director is deprecated); dest is - // forced to parsedURL rather than joined with the inbound path, matching - // the previous Director's behavior. proxy := &httputil.ReverseProxy{ Rewrite: func(pr *httputil.ProxyRequest) { dest := *parsedURL @@ -419,9 +413,6 @@ func (s *WorkspaceServer) httpPortForwardHandler(w http.ResponseWriter, r *http. parsedURL.Host = "127.0.0.1:" + targetPort log.Debugf("httpPortForwardHandler: final target URL=%s", parsedURL.String()) - // Build the reverse proxy with Rewrite (Director is deprecated); dest is - // forced to parsedURL rather than joined with the inbound path, matching - // the previous Director's behavior. proxy := &httputil.ReverseProxy{ Rewrite: func(pr *httputil.ProxyRequest) { dest := *parsedURL @@ -444,9 +435,7 @@ func (s *WorkspaceServer) httpPortForwardHandler(w http.ResponseWriter, r *http. proxy.ServeHTTP(w, r) } -// addForwardedFor sets X-Forwarded-For on the outbound proxy request, -// replicating the behavior ReverseProxy applies automatically when using -// the deprecated Director field but not when using Rewrite. +// addForwardedFor sets X-Forwarded-For on the outbound proxy request. func addForwardedFor(pr *httputil.ProxyRequest) { clientIP, _, err := net.SplitHostPort(pr.In.RemoteAddr) if err != nil { From e0d026c5aa1fbc0f96cbe96c03dadb1aeb1fc774 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Fri, 7 Aug 2026 00:18:20 +0000 Subject: [PATCH 4/6] fix: apply CodeRabbit auto-fixes Fixed 1 file(s) based on 1 unresolved review comment. Co-authored-by: CodeRabbit --- pkg/ts/workspace_server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/ts/workspace_server.go b/pkg/ts/workspace_server.go index 3a26ed955..2836db2aa 100644 --- a/pkg/ts/workspace_server.go +++ b/pkg/ts/workspace_server.go @@ -441,7 +441,7 @@ func addForwardedFor(pr *httputil.ProxyRequest) { if err != nil { return } - prior, ok := pr.Out.Header["X-Forwarded-For"] + prior, ok := pr.In.Header["X-Forwarded-For"] omit := ok && prior == nil if len(prior) > 0 { clientIP = strings.Join(prior, ", ") + ", " + clientIP From 26c18b9e1d7adb8832efc6f2f7652098170d1e82 Mon Sep 17 00:00:00 2001 From: Samuel K Date: Fri, 7 Aug 2026 01:32:56 +0000 Subject: [PATCH 5/6] Revert "fix: apply CodeRabbit auto-fixes" This reverts commit e0d026c5aa1fbc0f96cbe96c03dadb1aeb1fc774. --- pkg/ts/workspace_server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/ts/workspace_server.go b/pkg/ts/workspace_server.go index 2836db2aa..3a26ed955 100644 --- a/pkg/ts/workspace_server.go +++ b/pkg/ts/workspace_server.go @@ -441,7 +441,7 @@ func addForwardedFor(pr *httputil.ProxyRequest) { if err != nil { return } - prior, ok := pr.In.Header["X-Forwarded-For"] + prior, ok := pr.Out.Header["X-Forwarded-For"] omit := ok && prior == nil if len(prior) > 0 { clientIP = strings.Join(prior, ", ") + ", " + clientIP From 44f6b21344654f35838f36a19999dc888ba3f6ac Mon Sep 17 00:00:00 2001 From: Samuel K Date: Fri, 7 Aug 2026 01:36:33 +0000 Subject: [PATCH 6/6] Reapply "fix: apply CodeRabbit auto-fixes" This reverts commit 26c18b9e1d7adb8832efc6f2f7652098170d1e82. --- pkg/ts/workspace_server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/ts/workspace_server.go b/pkg/ts/workspace_server.go index 3a26ed955..2836db2aa 100644 --- a/pkg/ts/workspace_server.go +++ b/pkg/ts/workspace_server.go @@ -441,7 +441,7 @@ func addForwardedFor(pr *httputil.ProxyRequest) { if err != nil { return } - prior, ok := pr.Out.Header["X-Forwarded-For"] + prior, ok := pr.In.Header["X-Forwarded-For"] omit := ok && prior == nil if len(prior) > 0 { clientIP = strings.Join(prior, ", ") + ", " + clientIP