Skip to content

refactor(pkg): reduce cyclomatic complexity below cyclop threshold#765

Merged
skevetter merged 1 commit into
mainfrom
refactor/cyclop-pkg
Jul 26, 2026
Merged

refactor(pkg): reduce cyclomatic complexity below cyclop threshold#765
skevetter merged 1 commit into
mainfrom
refactor/cyclop-pkg

Conversation

@skevetter

@skevetter skevetter commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Summary

Decomposes functions in pkg/ that exceeded the golangci-lint cyclop max-complexity: 8 into well-named helpers (guard clauses, extracted predicates, param/result structs, switch/lookup maps), preserving behavior.

Part 2 of 2 of a repo-wide cyclop cleanup (companion PR covers cmd/, e2e/, hack/).

Latent bug fixes surfaced during review

While reducing complexity, review (CodeRabbit + independent adversarial passes) surfaced a few pre-existing bugs, fixed here as they touch the same code:

  • types: LifecycleHook named array-of-strings commands used an unchecked type assertion that panicked on non-string elements; now returns ErrUnsupportedType.
  • ssh/config: transformHostSection wrapped the (nil) file-open error instead of the scanner error on parse failure.
  • deploy: loftPodFailureError used mixed implicit/explicit fmt verbs, dropping reason and duplicating out; now uses explicit indices.
  • fleet: user-supplied IDE version was interpolated into a shell command unquoted; now regex-validated and %q-quoted.
  • copy: Directory used os.Stat (follows links) for the type switch, so symlinks were dereferenced and the os.ModeSymlink branch was dead; now uses entry.Info() (Lstat) so symlinks are preserved.
  • setup: writePlatformSSHKeys stale-key removal condition was inverted (left old platform_git_ssh_<i> files on disk when the key count shrank); corrected, and stale files are now removed on write failure.
  • gitsshsigning: removeSignatureHelper now strips CRLF (\r\n) so CRLF-terminated git configs are handled cleanly.
  • credentials/server: unmapped routes now return 404 (was empty 200); added ReadHeaderTimeout.
  • ts/workspace_server: two goroutines were serving different muxes on the same listener (racy, path-dependent routing); merged into one mux.
  • daemonclient/form, platform/form: boolean parameters absent from an instance now honor their configured default (BoolValue) on interactive update instead of silently defaulting to false; unchecked value.(string) assertions replaced with type-safe handling.
  • daemonclient/delete: parseGracePeriod now rejects <= 0 durations (a "0s" grace period previously produced an instant-cancel context).
  • daemon/agent: RemoveDaemon now treats systemctl disable's "does not exist" output as a no-op (previously only "not loaded" from stop was ignored).
  • netstat: guarded a /proc/<pid>/stat field access against malformed input.

Known follow-up (not addressed here)

  • ssh/server — when SSH agent-forwarding setup fails, the session is terminated (exitWithError), matching current/origin/main behavior. Arguably it should log and continue with agent forwarding disabled (a non-essential convenience) rather than killing the session. Left as-is to keep this PR behavior-preserving on that path; tracked as a follow-up.

go build ./..., go vet, and package tests pass; golangci-lint (only-new-issues vs main) is clean.

Summary by CodeRabbit

  • New Features

    • Added a way to count local workspaces for a selected context.
    • Improved workspace, container, and Kubernetes workflow handling.
  • Bug Fixes

    • Improved validation and error reporting for configuration, mounts, options, credentials, and network data.
    • Fixed edge cases involving missing files, invalid cached content, unreachable workspaces, and incomplete container status information.
    • Improved handling of SSH, Docker, Git, and platform credentials.
  • Refactor

    • Streamlined internal workflows across workspace management, devcontainer builds, IDE setup, and port forwarding without changing expected behavior.

@netlify

netlify Bot commented Jul 26, 2026

Copy link
Copy Markdown

Deploy Preview for images-devsy-sh canceled.

Name Link
🔨 Latest commit 9e40c85
🔍 Latest deploy log https://app.netlify.com/projects/images-devsy-sh/deploys/6a6682f5feb9b400083473de

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@skevetter, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 5 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1dee28f5-0ad3-4d2b-b56b-684aa4d83466

📥 Commits

Reviewing files that changed from the base of the PR and between 1d341ab and 9e40c85.

📒 Files selected for processing (76)
  • pkg/agent/agent.go
  • pkg/agent/binary.go
  • pkg/agent/delivery/factory.go
  • pkg/agent/tunnelserver/tunnelserver.go
  • pkg/client/clientimplementation/daemonclient/client.go
  • pkg/client/clientimplementation/daemonclient/delete.go
  • pkg/client/clientimplementation/daemonclient/form.go
  • pkg/client/clientimplementation/daemonclient/up.go
  • pkg/command/background.go
  • pkg/config/config.go
  • pkg/copy/copy.go
  • pkg/credentials/server.go
  • pkg/daemon/agent/daemon.go
  • pkg/daemon/platform/workspace_watcher.go
  • pkg/devcontainer/build/options.go
  • pkg/devcontainer/buildkit/buildkit.go
  • pkg/devcontainer/buildkit/cache.go
  • pkg/devcontainer/buildkit/remote.go
  • pkg/devcontainer/config/config.go
  • pkg/devcontainer/config/merge.go
  • pkg/devcontainer/config/parse_test.go
  • pkg/devcontainer/config/result.go
  • pkg/devcontainer/config/substitute.go
  • pkg/devcontainer/feature/extend.go
  • pkg/devcontainer/feature/features.go
  • pkg/devcontainer/prebuild.go
  • pkg/devcontainer/setup/setup.go
  • pkg/devcontainer/single.go
  • pkg/dockercredentials/dockercredentials.go
  • pkg/dockerfile/parse.go
  • pkg/driver/kubernetes/driver.go
  • pkg/driver/kubernetes/init_container.go
  • pkg/driver/kubernetes/pullsecrets.go
  • pkg/driver/kubernetes/pvc.go
  • pkg/driver/kubernetes/run.go
  • pkg/driver/kubernetes/serviceaccount.go
  • pkg/driver/kubernetes/wait.go
  • pkg/extract/compress.go
  • pkg/extract/extract.go
  • pkg/gitsshsigning/helper.go
  • pkg/ide/fleet/fleet.go
  • pkg/ide/ideparse/parse.go
  • pkg/ide/jetbrains/generic.go
  • pkg/ide/rstudio/rstudio.go
  • pkg/ide/vscode/vscode.go
  • pkg/inject/inject.go
  • pkg/netstat/netstat_util.go
  • pkg/netstat/watcher.go
  • pkg/options/resolve.go
  • pkg/options/resolve_test.go
  • pkg/options/resolver/parse.go
  • pkg/options/resolver/resolve.go
  • pkg/options/resolver/resolver.go
  • pkg/options/resolver/util.go
  • pkg/platform/client/client.go
  • pkg/platform/deploy.go
  • pkg/platform/form/form.go
  • pkg/platform/instance.go
  • pkg/platform/kubeconfig.go
  • pkg/platform/owner.go
  • pkg/platform/parameters/parameters.go
  • pkg/platform/remotecommand/client.go
  • pkg/provider/env.go
  • pkg/provider/parse.go
  • pkg/shell/shell.go
  • pkg/ssh/config.go
  • pkg/ssh/server/ssh.go
  • pkg/telemetry/collect.go
  • pkg/ts/workspace_server.go
  • pkg/tunnel/browser.go
  • pkg/tunnel/forwarder.go
  • pkg/types/types.go
  • pkg/util/homedir.go
  • pkg/workspace/exec.go
  • pkg/workspace/list.go
  • pkg/workspace/workspace.go
📝 Walkthrough

Walkthrough

This PR refactors repository subsystems by extracting validation, orchestration, persistence, parsing, networking, Kubernetes, workspace, IDE, and utility logic into focused unexported helpers while preserving existing exported APIs.

Changes

Repository-wide helper extraction

Layer / File(s) Summary
Agent and client service flows
pkg/agent/..., pkg/client/..., pkg/command/..., pkg/config/..., pkg/daemon/...
Workspace, delivery, credential, daemon, HTTP, and watcher flows are reorganized into dedicated helpers.
Devcontainer build and configuration
pkg/devcontainer/..., pkg/dockercredentials/..., pkg/dockerfile/...
BuildKit options, cache handling, feature caching, prebuild publishing, mounts, substitutions, credentials, and Dockerfile parsing are split into helper stages.
Kubernetes driver orchestration
pkg/driver/kubernetes/...
Pod construction, reconciliation, secrets, PVCs, service accounts, initialization, deletion, and readiness evaluation are modularized.
Option resolution and validation
pkg/options/...
Option parsing, dependency validation, dynamic resolution, persistence, and tests delegate to focused helpers.
Platform and interactive flows
pkg/platform/...
Login, deployment, forms, readiness polling, kubeconfig creation, ownership, parameter validation, and remote command handling are reorganized.
Network, shell, and SSH utilities
pkg/netstat/..., pkg/shell/..., pkg/ssh/..., pkg/tunnel/..., pkg/telemetry/..., pkg/ts/...
Socket parsing, forwarding, shell execution, SSH callbacks, backhaul setup, telemetry, and HTTP serving use extracted helpers.
Types and workspace/IDE orchestration
pkg/types/..., pkg/util/..., pkg/provider/..., pkg/workspace/..., pkg/ide/..., pkg/inject/...
JSON conversion, home-directory lookup, provider validation, workspace execution/listing/provisioning, IDE flows, and injection handling are decomposed into smaller functions.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main refactor goal and matches the changes across pkg/.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@netlify

netlify Bot commented Jul 26, 2026

Copy link
Copy Markdown

Deploy Preview for devsydev ready!

Name Link
🔨 Latest commit 9e40c85
🔍 Latest deploy log https://app.netlify.com/projects/devsydev/deploys/6a6682f5cf122900081f3e38
😎 Deploy Preview https://deploy-preview-765--devsydev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@skevetter
skevetter force-pushed the refactor/cyclop-pkg branch 4 times, most recently from b132f15 to 0471ec9 Compare July 26, 2026 17:25
@skevetter
skevetter marked this pull request as ready for review July 26, 2026 17:50

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
pkg/devcontainer/setup/setup.go (1)

695-733: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Stale SSH key cleanup condition is inverted — old keys are never removed.

writePlatformSSHKeys overwrites indices 0..keyCount-1, so the genuinely stale files are the ones with index >= keyCount. The current check skips exactly those (continue) and instead removes the files that are about to be overwritten anyway (index < keyCount). Result: when the number of configured platform SSH keys shrinks, old unused private key files at higher indices are left behind indefinitely.

🔒 Proposed fix: invert the skip condition
-		if index >= keyCount {
+		if index < keyCount {
 			continue
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/devcontainer/setup/setup.go` around lines 695 - 733, Correct the
stale-file filtering in removeStalePlatformSSHKeys: skip files whose parsed
index is less than keyCount, and remove files with index greater than or equal
to keyCount. Preserve the existing filename filtering, parsing behavior, and
warning handling.
pkg/ts/workspace_server.go (1)

239-268: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Two goroutines serve the same runnerProxyListener with different muxes — requests can be routed to the wrong handler.

The git-credentials and docker-credentials goroutines both call serveMux(runnerProxyListener, mux, ...) on the identical listener, each with a mux that only knows its own path. http.Serve doesn't exclusively own a listener; each incoming connection is accepted by whichever goroutine's Accept() wins the race, so a /docker-credentials request landing on the git-only server (or vice versa) gets a 404.

🐛 Proposed fix: register both handlers on one mux, serve once
 	// Setup HTTP handler for git credentials
 	go func() {
 		mux := http.NewServeMux()
 		transport := &http.Transport{DialContext: s.tsServer.Dial}
 		mux.HandleFunc("/git-credentials", func(w http.ResponseWriter, r *http.Request) {
 			s.gitCredentialsHandler(w, r, lc, transport, projectName, workspaceName)
 		})
-		serveMux(runnerProxyListener, mux, "HTTP runner proxy server error: %v")
-	}()
-
-	// Setup HTTP handler for docker credentials.
-	go func() {
-		mux := http.NewServeMux()
-		transport := &http.Transport{DialContext: s.tsServer.Dial}
 		mux.HandleFunc("/docker-credentials", func(w http.ResponseWriter, r *http.Request) {
 			s.dockerCredentialsHandler(w, r, lc, transport, projectName, workspaceName)
 		})
+		serveMux(runnerProxyListener, mux, "HTTP runner proxy server error: %v")
 	}()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/ts/workspace_server.go` around lines 239 - 268, Combine the
git-credentials and docker-credentials routes into a single mux and serve it
once on runnerProxyListener. Keep each route bound to its existing handler and
transport setup, but remove the two competing serveMux goroutines so requests
are dispatched by path reliably.
🧹 Nitpick comments (12)
pkg/driver/kubernetes/init_container.go (1)

116-131: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Two identical container-merge helpers were extracted instead of one. mergeInitContainer and mergeDevsyContainer apply the same rules (Env prepend, EnvFrom/Ports/ImagePullPolicy adoption, VolumeMounts prepend, SecurityContext fallback) to *corev1.Container; the shared root cause is duplicated merge logic that will now drift independently.

  • pkg/driver/kubernetes/init_container.go#L116-L131: replace mergeInitContainer with a single shared mergeContainer(dst, src *corev1.Container) helper.
  • pkg/driver/kubernetes/run.go#L582-L598: drop mergeDevsyContainer and call the shared helper from getContainers.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/driver/kubernetes/init_container.go` around lines 116 - 131, Replace
mergeInitContainer in pkg/driver/kubernetes/init_container.go:116-131 with the
shared mergeContainer(dst, src *corev1.Container) helper, preserving the
existing merge rules. In pkg/driver/kubernetes/run.go:582-598, remove
mergeDevsyContainer and update getContainers to call mergeContainer instead.
pkg/driver/kubernetes/run.go (1)

318-329: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

cap shadows the predeclared builtin.

Rename the loop variable (e.g. c) to avoid shadowing cap; some linters (predeclared, revive) flag this.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/driver/kubernetes/run.go` around lines 318 - 329, Rename the loop
variable in buildCapabilities from cap to a non-shadowing name such as c, and
update its use when appending to capabilities.Add; preserve the existing
capability conversion and return behavior.
pkg/driver/kubernetes/driver.go (1)

241-259: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Redundant secretExists probe; consider aligning the pull-secret flag check.

DeleteSecret already short-circuits via secretExists (pkg/driver/kubernetes/pullsecrets.go Line 103), so the guard on Line 243 adds a second API GET. Also, KubernetesPullSecretsEnabled != "" here differs from == pkgconfig.BoolTrue used in ensurePullSecrets (pkg/driver/kubernetes/run.go Line 422); harmless today since delete is a no-op, but the divergence is easy to misread.

♻️ Proposed simplification
 func (k *KubernetesDriver) deleteWorkspaceSecrets(ctx context.Context, workspaceId string) error {
 	// delete daemon config secret
-	if k.secretExists(ctx, getDaemonSecretName(workspaceId)) {
-		log.Infof("Delete daemon config secret %q", workspaceId)
-		if err := k.DeleteSecret(ctx, getDaemonSecretName(workspaceId)); err != nil {
-			return err
-		}
-	}
+	log.Infof("Delete daemon config secret %q", workspaceId)
+	if err := k.DeleteSecret(ctx, getDaemonSecretName(workspaceId)); err != nil {
+		return err
+	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/driver/kubernetes/driver.go` around lines 241 - 259, Update
deleteWorkspaceSecrets to remove the redundant secretExists guard and call
DeleteSecret directly for the daemon secret, relying on its existing no-op
behavior. Align the pull-secret condition with ensurePullSecrets by checking
KubernetesPullSecretsEnabled against pkgconfig.BoolTrue, while preserving the
current error propagation.
pkg/options/resolve_test.go (2)

664-665: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Mark the new test helpers with t.Helper().

Without it, assert.* failures are attributed to runResolveTestCase/assertResolvedOptions rather than the caller.

♻️ Proposed change
 func runResolveTestCase(t *testing.T, tc testCase) {
+	t.Helper()
 	r := resolver.New(tc.UserValues, tc.ExtraValues, buildResolverOpts(tc)...)
 ) {
+	t.Helper()
 	strOptions := map[string]string{}

Also applies to: 699-704

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/options/resolve_test.go` around lines 664 - 665, Mark the test helper
functions runResolveTestCase and assertResolvedOptions with t.Helper() at their
start so assertion failures are attributed to the calling test.

659-662: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use t.Run subtests now that each case is a function call.

Failures currently report only the helper's line; tc.Name is passed to some assertions but not all (assertResolvedOptions doesn't include it).

♻️ Proposed change
 	for _, tc := range testCases {
-		runResolveTestCase(t, tc)
+		t.Run(tc.Name, func(t *testing.T) {
+			runResolveTestCase(t, tc)
+		})
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/options/resolve_test.go` around lines 659 - 662, Update the test-case
loop in the resolve tests to wrap each runResolveTestCase invocation in t.Run
using tc.Name as the subtest name, so failures are attributed to the specific
case even when assertions such as assertResolvedOptions omit the name.
pkg/util/homedir.go (1)

52-67: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Named results on homeFromPlatform are never used.

Every path returns explicitly, and the inner case "windows" shadows home/err. Either drop the names or document done in the signature only via the comment (already present).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/util/homedir.go` around lines 52 - 67, Remove the unused named return
values from homeFromPlatform and give the function an unnamed return signature,
preserving all existing explicit return paths and behavior.
pkg/options/resolver/util.go (1)

126-162: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

variableDependencyParams duplicates variableDependenciesParams except for deps/dep.

Could collapse by passing (p variableDependenciesParams, dep string) to validateVariableDependency instead of a second near-identical struct.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/options/resolver/util.go` around lines 126 - 162, Remove the duplicate
variableDependencyParams type and change validateVariableDependency to accept
variableDependenciesParams plus a dep string. Update addVariableDependencies to
pass the existing p and current dep while preserving all validation behavior.
pkg/options/resolve.go (1)

443-448: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Nil providerValues now takes a different branch.

When providerValues is nil, this guard is skipped entirely and the option can be deleted purely on Global, whereas a plain lookup on a nil map would report !ok and keep it. Current callers pass devConfig.ProviderOptions(...) (never nil), so this is latent only — dropping the nil check makes the semantics uniform.

♻️ Simplify to a plain lookup
-	if p.providerValues != nil {
-		if _, ok := p.providerValues[p.k]; !ok {
-			return false
-		}
+	if _, ok := p.providerValues[p.k]; !ok {
+		return false
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/options/resolve.go` around lines 443 - 448, Update the provider-value
check in the option filtering logic to use a plain lookup on p.providerValues
without guarding against nil, so nil maps produce !ok and preserve the option.
Keep the existing p.k lookup and return behavior unchanged.
pkg/platform/deploy.go (1)

177-183: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Plumb the caller's context into the log fetch instead of context.Background().

loftPodFailureError is reached from a PollUntilContextTimeout callback; using context.Background() for GetLogs means this call ignores cancellation/timeout and can block the wait loop.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/platform/deploy.go` around lines 177 - 183, Update the GetLogs call in
loftPodFailureError to use the caller-provided context instead of
context.Background(), preserving cancellation and timeout propagation from the
PollUntilContextTimeout callback.
pkg/platform/kubeconfig.go (1)

41-41: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Local kube identifier shadows the newly imported kube package.

The file now imports github.com/devsy-org/devsy/pkg/platform/kube (line 14) for kube.Interface. Renaming these to k8sOpts avoids future breakage if the package is referenced in these scopes.

Also applies to: 83-87

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/platform/kubeconfig.go` at line 41, Rename the local Kubernetes options
identifier currently declared as kube in the affected scopes to k8sOpts,
including its references around the later usage, so it no longer shadows the
imported kube package. Keep the existing behavior unchanged.
pkg/credentials/server.go (1)

93-102: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Return 404 for unmapped paths.

Returning without writing yields an empty 200 OK, which is indistinguishable from a successful empty credential response for clients.

♻️ Proposed change
 		handler, ok := routes[request.URL.Path]
 		if !ok {
+			http.NotFound(writer, request)
 			return
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/credentials/server.go` around lines 93 - 102, Update the route lookup in
the HTTP handler returned by the server handler function so unmapped request
paths write an HTTP 404 response before returning; preserve the existing handler
invocation and 500 error behavior for mapped routes.
pkg/client/clientimplementation/daemonclient/delete.go (1)

68-78: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Log invalid grace-period values instead of silently dropping them.

A malformed --grace-period silently degrades to "no timeout" with no signal to the user.

♻️ Proposed change
 	duration, err := time.ParseDuration(raw)
 	if err != nil {
+		log.Warnf("Invalid grace period %q, ignoring: %v", raw, err)
 		return nil
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/client/clientimplementation/daemonclient/delete.go` around lines 68 - 78,
Update parseGracePeriod to log invalid non-empty grace-period values when
time.ParseDuration fails, while preserving the nil return for malformed input
and empty strings. Use the existing logging mechanism available in the
surrounding delete-client code rather than silently discarding the parse error.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/agent/tunnelserver/tunnelserver.go`:
- Around line 569-583: Update workspaceIgnoreExcludes to close the file opened
by os.Open after ignorefile.ReadAll completes, including when reading fails,
while preserving the existing excludes and warning behavior.

In `@pkg/client/clientimplementation/daemonclient/client.go`:
- Around line 327-349: Update workspaceUnreachableError to handle a nil instance
before accessing instance.Status, including the (nil, nil) result from
LocalClient.GetWorkspace in the unreachable-host path. Return an appropriate
workspace retrieval error for nil instances, while preserving the existing
getWorkspaceErr, status checks, and reachability error behavior.

In `@pkg/client/clientimplementation/daemonclient/form.go`:
- Around line 273-302: Update fieldParametersWithValues to avoid direct string
assertions on values returned by getDeepValue. Preserve string values as-is,
safely convert native persisted scalar types such as int and bool before
assigning StringValue, and ensure boolean parsing only operates on a valid
string representation so interactive updates cannot panic.

In `@pkg/devcontainer/config/config.go`:
- Around line 590-612: The applyMountField function indexes splitted2[1] without
validating that a value exists, causing malformed mount fields to panic. Check
for a missing value before handling recognized keys, and preserve or reject the
original malformed token consistently instead of assigning fields from it; valid
key-value parsing must remain unchanged.
- Around line 626-650: The unmarshalMountObject method currently panics when an
element of other is not a string. Change it to return an error, propagate
types.ErrUnsupportedType when any otherInterface element fails string
validation, and update its caller to return that error while preserving
successful string conversion.

In `@pkg/devcontainer/prebuild.go`:
- Around line 137-140: Update the image reference construction in the prebuild
image tagging flow to remove only the final tag suffix, preserving registry
ports and repository path components. Replace the current first-colon split used
for imageRepoName with logic that derives the repository from the last tag
separator before appending each tag.

In `@pkg/gitsshsigning/helper.go`:
- Around line 178-186: Update removeSignatureHelper to strip both carriage
return and newline characters from each line before passing it to
gitConfigFilter.process, preserving clean output for CRLF-terminated
configuration files while leaving other processing unchanged.

In `@pkg/platform/deploy.go`:
- Around line 205-212: Fix the format argument mapping in the error construction
around the return statement so the output uses pkgconfig.ProductNamePro, out,
message, and reason exactly once in their intended placeholders. Use explicit
argument indexes consistently for every format verb, preserving the existing
message text and support URL.

In `@pkg/platform/form/form.go`:
- Around line 288-301: Update assignFieldValue to replace both unchecked
value.(string) assertions with comma-ok type assertions. For boolean parameters,
parse only when the value is a string; for the general path, assign StringValue
only when the value is a string, otherwise preserve the existing default-value
behavior without panicking.

In `@pkg/platform/instance.go`:
- Around line 274-288: Guard waitForInstanceTimeoutError against a nil
updatedInstance before accessing readiness, template-sync, or Status.Conditions
fields. Update both affected call paths around PollUntilContextTimeout so an
already-cancelled context with no poll result returns a safe timeout error
without dereferencing nil.

In `@pkg/platform/kubeconfig.go`:
- Around line 329-331: Update the error wrapping in the GetKubeConfig branch to
use the message “get virtual cluster kube config: %w” instead of identifying it
as direct cluster endpoint token creation. Keep the existing error propagation
unchanged so the ingress and direct endpoint paths remain distinguishable.

In `@pkg/telemetry/collect.go`:
- Around line 185-207: Cache the result of d.client.WorkspaceConfig() in
buildEventProperties before checking it, then reuse that single value for
source_type and ide. Preserve the existing provider and event-property behavior
while ensuring the cached configuration is nil-checked before field access.

In `@pkg/util/homedir.go`:
- Around line 108-113: Update the passwd parsing in UserHomeDir so an empty
passwdParts[5] is treated as unavailable rather than authoritative: only return
success when the home field is non-empty, otherwise continue to the existing
shell-based fallback. Preserve the current behavior for valid home fields and
malformed entries.

---

Outside diff comments:
In `@pkg/devcontainer/setup/setup.go`:
- Around line 695-733: Correct the stale-file filtering in
removeStalePlatformSSHKeys: skip files whose parsed index is less than keyCount,
and remove files with index greater than or equal to keyCount. Preserve the
existing filename filtering, parsing behavior, and warning handling.

In `@pkg/ts/workspace_server.go`:
- Around line 239-268: Combine the git-credentials and docker-credentials routes
into a single mux and serve it once on runnerProxyListener. Keep each route
bound to its existing handler and transport setup, but remove the two competing
serveMux goroutines so requests are dispatched by path reliably.

---

Nitpick comments:
In `@pkg/client/clientimplementation/daemonclient/delete.go`:
- Around line 68-78: Update parseGracePeriod to log invalid non-empty
grace-period values when time.ParseDuration fails, while preserving the nil
return for malformed input and empty strings. Use the existing logging mechanism
available in the surrounding delete-client code rather than silently discarding
the parse error.

In `@pkg/credentials/server.go`:
- Around line 93-102: Update the route lookup in the HTTP handler returned by
the server handler function so unmapped request paths write an HTTP 404 response
before returning; preserve the existing handler invocation and 500 error
behavior for mapped routes.

In `@pkg/driver/kubernetes/driver.go`:
- Around line 241-259: Update deleteWorkspaceSecrets to remove the redundant
secretExists guard and call DeleteSecret directly for the daemon secret, relying
on its existing no-op behavior. Align the pull-secret condition with
ensurePullSecrets by checking KubernetesPullSecretsEnabled against
pkgconfig.BoolTrue, while preserving the current error propagation.

In `@pkg/driver/kubernetes/init_container.go`:
- Around line 116-131: Replace mergeInitContainer in
pkg/driver/kubernetes/init_container.go:116-131 with the shared
mergeContainer(dst, src *corev1.Container) helper, preserving the existing merge
rules. In pkg/driver/kubernetes/run.go:582-598, remove mergeDevsyContainer and
update getContainers to call mergeContainer instead.

In `@pkg/driver/kubernetes/run.go`:
- Around line 318-329: Rename the loop variable in buildCapabilities from cap to
a non-shadowing name such as c, and update its use when appending to
capabilities.Add; preserve the existing capability conversion and return
behavior.

In `@pkg/options/resolve_test.go`:
- Around line 664-665: Mark the test helper functions runResolveTestCase and
assertResolvedOptions with t.Helper() at their start so assertion failures are
attributed to the calling test.
- Around line 659-662: Update the test-case loop in the resolve tests to wrap
each runResolveTestCase invocation in t.Run using tc.Name as the subtest name,
so failures are attributed to the specific case even when assertions such as
assertResolvedOptions omit the name.

In `@pkg/options/resolve.go`:
- Around line 443-448: Update the provider-value check in the option filtering
logic to use a plain lookup on p.providerValues without guarding against nil, so
nil maps produce !ok and preserve the option. Keep the existing p.k lookup and
return behavior unchanged.

In `@pkg/options/resolver/util.go`:
- Around line 126-162: Remove the duplicate variableDependencyParams type and
change validateVariableDependency to accept variableDependenciesParams plus a
dep string. Update addVariableDependencies to pass the existing p and current
dep while preserving all validation behavior.

In `@pkg/platform/deploy.go`:
- Around line 177-183: Update the GetLogs call in loftPodFailureError to use the
caller-provided context instead of context.Background(), preserving cancellation
and timeout propagation from the PollUntilContextTimeout callback.

In `@pkg/platform/kubeconfig.go`:
- Line 41: Rename the local Kubernetes options identifier currently declared as
kube in the affected scopes to k8sOpts, including its references around the
later usage, so it no longer shadows the imported kube package. Keep the
existing behavior unchanged.

In `@pkg/util/homedir.go`:
- Around line 52-67: Remove the unused named return values from homeFromPlatform
and give the function an unnamed return signature, preserving all existing
explicit return paths and behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2a350102-cf90-40c9-b81f-c85703980a67

📥 Commits

Reviewing files that changed from the base of the PR and between 40594c0 and c42894e.

📒 Files selected for processing (76)
  • pkg/agent/agent.go
  • pkg/agent/binary.go
  • pkg/agent/delivery/factory.go
  • pkg/agent/tunnelserver/tunnelserver.go
  • pkg/client/clientimplementation/daemonclient/client.go
  • pkg/client/clientimplementation/daemonclient/delete.go
  • pkg/client/clientimplementation/daemonclient/form.go
  • pkg/client/clientimplementation/daemonclient/up.go
  • pkg/command/background.go
  • pkg/config/config.go
  • pkg/copy/copy.go
  • pkg/credentials/server.go
  • pkg/daemon/agent/daemon.go
  • pkg/daemon/platform/workspace_watcher.go
  • pkg/devcontainer/build/options.go
  • pkg/devcontainer/buildkit/buildkit.go
  • pkg/devcontainer/buildkit/cache.go
  • pkg/devcontainer/buildkit/remote.go
  • pkg/devcontainer/config/config.go
  • pkg/devcontainer/config/merge.go
  • pkg/devcontainer/config/parse_test.go
  • pkg/devcontainer/config/result.go
  • pkg/devcontainer/config/substitute.go
  • pkg/devcontainer/feature/extend.go
  • pkg/devcontainer/feature/features.go
  • pkg/devcontainer/prebuild.go
  • pkg/devcontainer/setup/setup.go
  • pkg/devcontainer/single.go
  • pkg/dockercredentials/dockercredentials.go
  • pkg/dockerfile/parse.go
  • pkg/driver/kubernetes/driver.go
  • pkg/driver/kubernetes/init_container.go
  • pkg/driver/kubernetes/pullsecrets.go
  • pkg/driver/kubernetes/pvc.go
  • pkg/driver/kubernetes/run.go
  • pkg/driver/kubernetes/serviceaccount.go
  • pkg/driver/kubernetes/wait.go
  • pkg/extract/compress.go
  • pkg/extract/extract.go
  • pkg/gitsshsigning/helper.go
  • pkg/ide/fleet/fleet.go
  • pkg/ide/ideparse/parse.go
  • pkg/ide/jetbrains/generic.go
  • pkg/ide/rstudio/rstudio.go
  • pkg/ide/vscode/vscode.go
  • pkg/inject/inject.go
  • pkg/netstat/netstat_util.go
  • pkg/netstat/watcher.go
  • pkg/options/resolve.go
  • pkg/options/resolve_test.go
  • pkg/options/resolver/parse.go
  • pkg/options/resolver/resolve.go
  • pkg/options/resolver/resolver.go
  • pkg/options/resolver/util.go
  • pkg/platform/client/client.go
  • pkg/platform/deploy.go
  • pkg/platform/form/form.go
  • pkg/platform/instance.go
  • pkg/platform/kubeconfig.go
  • pkg/platform/owner.go
  • pkg/platform/parameters/parameters.go
  • pkg/platform/remotecommand/client.go
  • pkg/provider/env.go
  • pkg/provider/parse.go
  • pkg/shell/shell.go
  • pkg/ssh/config.go
  • pkg/ssh/server/ssh.go
  • pkg/telemetry/collect.go
  • pkg/ts/workspace_server.go
  • pkg/tunnel/browser.go
  • pkg/tunnel/forwarder.go
  • pkg/types/types.go
  • pkg/util/homedir.go
  • pkg/workspace/exec.go
  • pkg/workspace/list.go
  • pkg/workspace/workspace.go

Comment thread pkg/agent/tunnelserver/tunnelserver.go
Comment thread pkg/client/clientimplementation/daemonclient/client.go
Comment thread pkg/client/clientimplementation/daemonclient/form.go Outdated
Comment thread pkg/devcontainer/config/config.go
Comment thread pkg/devcontainer/config/config.go Outdated
Comment thread pkg/platform/form/form.go
Comment thread pkg/platform/instance.go
Comment thread pkg/platform/kubeconfig.go
Comment thread pkg/telemetry/collect.go
Comment thread pkg/util/homedir.go
@skevetter
skevetter marked this pull request as draft July 26, 2026 18:10
@skevetter
skevetter force-pushed the refactor/cyclop-pkg branch 5 times, most recently from 9af634c to 1d341ab Compare July 26, 2026 20:51
@skevetter
skevetter marked this pull request as ready for review July 26, 2026 21:26

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/platform/form/form.go (1)

489-505: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Route unknown AppParameter types to the string field in parameterFields.

Unlike the daemonclient path, pkg/platform/form/parameterFields uses param.Type directly and falls through when the value is unsupported, leaving field nil and appending it to the huh group. Add a default case that calls stringParameterField(param, title) for unknown/empty types.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/platform/form/form.go` around lines 489 - 505, Update the type switch in
parameterFields so its default branch routes unknown or empty param.Type values
through stringParameterField(param, title), ensuring fields never remain nil
while preserving the existing handling for supported types.
♻️ Duplicate comments (1)
pkg/platform/form/form.go (1)

254-310: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Non-string existing values now silently fall back to defaults.

The panic risk flagged previously is fixed, but for non-boolean parameters a YAML-decoded number (float64) or nested value still discards the user's saved value and reverts to DefaultValue. For type: number parameters stored as YAML scalars this is a visible regression in the update form.

🛠️ Proposed fix
 	if s, ok := value.(string); ok {
 		fieldParameter.StringValue = s
+	} else if value != nil {
+		fieldParameter.StringValue = fmt.Sprintf("%v", value)
 	} else {
 		fieldParameter.StringValue = fieldParameter.DefaultValue
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/platform/form/form.go` around lines 254 - 310, Update assignFieldValue so
non-boolean existing values, including YAML-decoded numbers and nested scalar
values, are preserved in the field parameter instead of falling back to
DefaultValue. Convert supported scalar values to the string representation
expected by StringValue, while retaining the existing default fallback only for
values that cannot be represented.
🧹 Nitpick comments (4)
pkg/driver/kubernetes/driver.go (2)

210-222: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prefer ptr.To(int64(5)) over the &[]int64{5}[0] idiom.

k8s.io/utils/ptr is already used elsewhere in this package (e.g. finalizePodSpec in pkg/driver/kubernetes/run.go).

♻️ Proposed tweak
 		Delete(ctx, workspaceId, metav1.DeleteOptions{
-			GracePeriodSeconds: &[]int64{5}[0],
+			GracePeriodSeconds: ptr.To(int64(5)),
 		})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/driver/kubernetes/driver.go` around lines 210 - 222, Replace the
`&[]int64{5}[0]` expression in the PVC deletion flow with `ptr.To(int64(5))`,
adding the existing `k8s.io/utils/ptr` import if needed. Keep the
`GracePeriodSeconds` value and the surrounding `Delete` error handling
unchanged.

241-256: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Redundant existence check and inconsistent KubernetesPullSecretsEnabled comparison.

DeleteSecret (pkg/driver/kubernetes/pullsecrets.go:99-116) already short-circuits via secretExists, so the guard on Line 243 doubles the API call. Also, creation uses == pkgconfig.BoolTrue (ensurePullSecrets in pkg/driver/kubernetes/run.go), while deletion uses != "", so an explicit "false" still triggers a pull-secret lookup. Deletion is idempotent so behavior is safe, but the comparisons should match.

♻️ Proposed simplification
 func (k *KubernetesDriver) deleteWorkspaceSecrets(ctx context.Context, workspaceId string) error {
 	// delete daemon config secret
-	if k.secretExists(ctx, getDaemonSecretName(workspaceId)) {
-		log.Infof("Delete daemon config secret %q", workspaceId)
-		if err := k.DeleteSecret(ctx, getDaemonSecretName(workspaceId)); err != nil {
-			return err
-		}
-	}
+	log.Infof("Delete daemon config secret %q", workspaceId)
+	if err := k.DeleteSecret(ctx, getDaemonSecretName(workspaceId)); err != nil {
+		return err
+	}
 
 	// delete pull secret
-	if k.options.KubernetesPullSecretsEnabled != "" {
+	if k.options.KubernetesPullSecretsEnabled == pkgconfig.BoolTrue {
 		log.Infof("Delete pull secret %q", workspaceId)
 		if err := k.DeleteSecret(ctx, getPullSecretsName(workspaceId)); err != nil {
 			return err
 		}
 	}

Note: if pull secrets could have been created under an older option value, keeping the permissive delete check is intentional — confirm before tightening.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/driver/kubernetes/driver.go` around lines 241 - 256, Update
deleteWorkspaceSecrets to rely directly on DeleteSecret for the daemon secret
instead of calling secretExists first, removing the redundant lookup while
preserving error propagation. Align the KubernetesPullSecretsEnabled condition
with ensurePullSecrets by using the same explicit enabled-value comparison,
unless backward compatibility requires retaining the permissive deletion
behavior.
pkg/driver/kubernetes/run.go (1)

104-189: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Check for an existing pod before building and ensuring Kubernetes resources.

runContainer calls buildPod first, and buildPod creates/refreshes the service account bindings, daemon config secret, and pull secrets before reconcileExistingPod can return true. If a skipped run should not mutate cluster resources, move the reconcile check before these ensure* calls or split the pure pod spec build from the cluster-resource preparation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/driver/kubernetes/run.go` around lines 104 - 189, Update runContainer to
call reconcileExistingPod before buildPod, returning immediately when skip is
true so skipped runs do not create or refresh Kubernetes resources through
buildPod’s ensureServiceAccount, ensureDaemonConfig, and ensurePullSecrets
calls. Preserve error propagation, and only build and run the pod when
reconciliation does not skip.
pkg/options/resolver/util.go (1)

98-124: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Guard against a nil option for symmetry.

validateChildDependency/validateVariableDependency defensively handle childOption == nil/depOption == nil, but option (from g.GetNode(optionName) in addDependency) is dereferenced without the same guard. Nodes can hold nil values (e.g. rootID is added with nil at line 182), so an early if option == nil { return nil } in addDependency would keep the invariants consistent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/options/resolver/util.go` around lines 98 - 124, Add an early nil check
for the parent option in addDependency before it calls validateChildDependency
or validateVariableDependency; return nil when option is nil. Preserve the
existing dependency validation behavior for non-nil options and avoid
dereferencing option before this guard.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/driver/kubernetes/run.go`:
- Around line 450-457: Update the existingOptions parsing near
DevsyLastAppliedAnnotation to first read and validate the annotation value,
calling json.Unmarshal only when it is non-empty. Skip parsing and error logging
for missing annotations while preserving the existing error log for invalid
non-empty annotation data.

---

Outside diff comments:
In `@pkg/platform/form/form.go`:
- Around line 489-505: Update the type switch in parameterFields so its default
branch routes unknown or empty param.Type values through
stringParameterField(param, title), ensuring fields never remain nil while
preserving the existing handling for supported types.

---

Duplicate comments:
In `@pkg/platform/form/form.go`:
- Around line 254-310: Update assignFieldValue so non-boolean existing values,
including YAML-decoded numbers and nested scalar values, are preserved in the
field parameter instead of falling back to DefaultValue. Convert supported
scalar values to the string representation expected by StringValue, while
retaining the existing default fallback only for values that cannot be
represented.

---

Nitpick comments:
In `@pkg/driver/kubernetes/driver.go`:
- Around line 210-222: Replace the `&[]int64{5}[0]` expression in the PVC
deletion flow with `ptr.To(int64(5))`, adding the existing `k8s.io/utils/ptr`
import if needed. Keep the `GracePeriodSeconds` value and the surrounding
`Delete` error handling unchanged.
- Around line 241-256: Update deleteWorkspaceSecrets to rely directly on
DeleteSecret for the daemon secret instead of calling secretExists first,
removing the redundant lookup while preserving error propagation. Align the
KubernetesPullSecretsEnabled condition with ensurePullSecrets by using the same
explicit enabled-value comparison, unless backward compatibility requires
retaining the permissive deletion behavior.

In `@pkg/driver/kubernetes/run.go`:
- Around line 104-189: Update runContainer to call reconcileExistingPod before
buildPod, returning immediately when skip is true so skipped runs do not create
or refresh Kubernetes resources through buildPod’s ensureServiceAccount,
ensureDaemonConfig, and ensurePullSecrets calls. Preserve error propagation, and
only build and run the pod when reconciliation does not skip.

In `@pkg/options/resolver/util.go`:
- Around line 98-124: Add an early nil check for the parent option in
addDependency before it calls validateChildDependency or
validateVariableDependency; return nil when option is nil. Preserve the existing
dependency validation behavior for non-nil options and avoid dereferencing
option before this guard.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9dd7e04d-8778-4bbc-9f21-f6c6022a2445

📥 Commits

Reviewing files that changed from the base of the PR and between c42894e and 1d341ab.

📒 Files selected for processing (76)
  • pkg/agent/agent.go
  • pkg/agent/binary.go
  • pkg/agent/delivery/factory.go
  • pkg/agent/tunnelserver/tunnelserver.go
  • pkg/client/clientimplementation/daemonclient/client.go
  • pkg/client/clientimplementation/daemonclient/delete.go
  • pkg/client/clientimplementation/daemonclient/form.go
  • pkg/client/clientimplementation/daemonclient/up.go
  • pkg/command/background.go
  • pkg/config/config.go
  • pkg/copy/copy.go
  • pkg/credentials/server.go
  • pkg/daemon/agent/daemon.go
  • pkg/daemon/platform/workspace_watcher.go
  • pkg/devcontainer/build/options.go
  • pkg/devcontainer/buildkit/buildkit.go
  • pkg/devcontainer/buildkit/cache.go
  • pkg/devcontainer/buildkit/remote.go
  • pkg/devcontainer/config/config.go
  • pkg/devcontainer/config/merge.go
  • pkg/devcontainer/config/parse_test.go
  • pkg/devcontainer/config/result.go
  • pkg/devcontainer/config/substitute.go
  • pkg/devcontainer/feature/extend.go
  • pkg/devcontainer/feature/features.go
  • pkg/devcontainer/prebuild.go
  • pkg/devcontainer/setup/setup.go
  • pkg/devcontainer/single.go
  • pkg/dockercredentials/dockercredentials.go
  • pkg/dockerfile/parse.go
  • pkg/driver/kubernetes/driver.go
  • pkg/driver/kubernetes/init_container.go
  • pkg/driver/kubernetes/pullsecrets.go
  • pkg/driver/kubernetes/pvc.go
  • pkg/driver/kubernetes/run.go
  • pkg/driver/kubernetes/serviceaccount.go
  • pkg/driver/kubernetes/wait.go
  • pkg/extract/compress.go
  • pkg/extract/extract.go
  • pkg/gitsshsigning/helper.go
  • pkg/ide/fleet/fleet.go
  • pkg/ide/ideparse/parse.go
  • pkg/ide/jetbrains/generic.go
  • pkg/ide/rstudio/rstudio.go
  • pkg/ide/vscode/vscode.go
  • pkg/inject/inject.go
  • pkg/netstat/netstat_util.go
  • pkg/netstat/watcher.go
  • pkg/options/resolve.go
  • pkg/options/resolve_test.go
  • pkg/options/resolver/parse.go
  • pkg/options/resolver/resolve.go
  • pkg/options/resolver/resolver.go
  • pkg/options/resolver/util.go
  • pkg/platform/client/client.go
  • pkg/platform/deploy.go
  • pkg/platform/form/form.go
  • pkg/platform/instance.go
  • pkg/platform/kubeconfig.go
  • pkg/platform/owner.go
  • pkg/platform/parameters/parameters.go
  • pkg/platform/remotecommand/client.go
  • pkg/provider/env.go
  • pkg/provider/parse.go
  • pkg/shell/shell.go
  • pkg/ssh/config.go
  • pkg/ssh/server/ssh.go
  • pkg/telemetry/collect.go
  • pkg/ts/workspace_server.go
  • pkg/tunnel/browser.go
  • pkg/tunnel/forwarder.go
  • pkg/types/types.go
  • pkg/util/homedir.go
  • pkg/workspace/exec.go
  • pkg/workspace/list.go
  • pkg/workspace/workspace.go
🚧 Files skipped from review as they are similar to previous changes (56)
  • pkg/devcontainer/config/result.go
  • pkg/agent/binary.go
  • pkg/command/background.go
  • pkg/provider/env.go
  • pkg/driver/kubernetes/serviceaccount.go
  • pkg/driver/kubernetes/init_container.go
  • pkg/devcontainer/buildkit/cache.go
  • pkg/telemetry/collect.go
  • pkg/extract/extract.go
  • pkg/devcontainer/config/substitute.go
  • pkg/dockercredentials/dockercredentials.go
  • pkg/dockerfile/parse.go
  • pkg/credentials/server.go
  • pkg/devcontainer/single.go
  • pkg/options/resolver/parse.go
  • pkg/devcontainer/buildkit/remote.go
  • pkg/devcontainer/setup/setup.go
  • pkg/ide/jetbrains/generic.go
  • pkg/devcontainer/build/options.go
  • pkg/options/resolve_test.go
  • pkg/netstat/watcher.go
  • pkg/driver/kubernetes/pullsecrets.go
  • pkg/platform/remotecommand/client.go
  • pkg/client/clientimplementation/daemonclient/delete.go
  • pkg/tunnel/browser.go
  • pkg/devcontainer/feature/extend.go
  • pkg/platform/instance.go
  • pkg/gitsshsigning/helper.go
  • pkg/devcontainer/config/merge.go
  • pkg/agent/delivery/factory.go
  • pkg/ide/fleet/fleet.go
  • pkg/devcontainer/config/parse_test.go
  • pkg/extract/compress.go
  • pkg/ide/vscode/vscode.go
  • pkg/types/types.go
  • pkg/ide/rstudio/rstudio.go
  • pkg/driver/kubernetes/wait.go
  • pkg/client/clientimplementation/daemonclient/up.go
  • pkg/platform/parameters/parameters.go
  • pkg/devcontainer/feature/features.go
  • pkg/workspace/exec.go
  • pkg/daemon/agent/daemon.go
  • pkg/ssh/config.go
  • pkg/client/clientimplementation/daemonclient/client.go
  • pkg/client/clientimplementation/daemonclient/form.go
  • pkg/inject/inject.go
  • pkg/options/resolver/resolver.go
  • pkg/util/homedir.go
  • pkg/agent/tunnelserver/tunnelserver.go
  • pkg/workspace/workspace.go
  • pkg/platform/client/client.go
  • pkg/platform/deploy.go
  • pkg/options/resolver/resolve.go
  • pkg/ssh/server/ssh.go
  • pkg/workspace/list.go
  • pkg/shell/shell.go

Comment thread pkg/driver/kubernetes/run.go
@skevetter
skevetter marked this pull request as draft July 26, 2026 21:46
@skevetter
skevetter force-pushed the refactor/cyclop-pkg branch from 1d341ab to 7c8e0b9 Compare July 26, 2026 21:51
Decompose functions in pkg/ that exceeded the golangci-lint cyclop
max-complexity of 8 into well-named helpers (guard clauses, extracted
predicates, param/result structs, switch/lookup maps), preserving behavior.
Extracted helpers bundle args into structs to respect the repo's revive
argument-limit/function-result-limit rules, and keep unexported methods
ordered after exported ones (funcorder).

Also fixes two pre-existing latent bugs surfaced during review:
- types: LifecycleHook named array commands used an unchecked type
  assertion that panicked on non-string elements; now returns
  ErrUnsupportedType via the existing stringArray helper.
- ssh/config: transformHostSection wrapped the (nil) file-open error
  instead of the scanner error on parse failure.

Sets ReadHeaderTimeout on the credentials http.Server (gosec G112).
@skevetter
skevetter force-pushed the refactor/cyclop-pkg branch from 7c8e0b9 to 9e40c85 Compare July 26, 2026 21:58
@skevetter
skevetter marked this pull request as ready for review July 26, 2026 22:21
@skevetter
skevetter enabled auto-merge (squash) July 26, 2026 22:30
@skevetter
skevetter merged commit 111d220 into main Jul 26, 2026
65 checks passed
@skevetter
skevetter deleted the refactor/cyclop-pkg branch July 26, 2026 22:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant