Skip to content

Conversation

@skevetter
Copy link
Owner

@skevetter skevetter commented Feb 4, 2026

  • refactor(binaries): move to provider package
  • fix: linting issues
  • fix: address feedback
  • fix: address comment feedback
  • fix: handle retryable errors
  • fix: http status code handling
  • fix: asset url reported with status error
  • fix: nitpicks

Summary by CodeRabbit

  • Refactor
    • Consolidated provider APIs and migrated workspace init to structured parameters for clearer flows.
  • Bug Fixes
    • More robust binary downloads with retries, backoff and checksum cleanup; tolerant daemon reload and safer file permissions.
  • Improvements
    • Richer, URL-aware HTTP download errors; options resolution now supports sub-options; environment construction centralized.
  • New Features
    • Remote workspace creation interface added.
  • Tests
    • Improved integration SSH test setup and context-aware execution; CI test timeout reduced.

Signed-off-by: Samuel K <skevetter@pm.me>
Signed-off-by: Samuel K <skevetter@pm.me>
Signed-off-by: Samuel K <skevetter@pm.me>
Signed-off-by: Samuel K <skevetter@pm.me>
Signed-off-by: Samuel K <skevetter@pm.me>
Signed-off-by: Samuel K <skevetter@pm.me>
Signed-off-by: Samuel K <skevetter@pm.me>
Signed-off-by: Samuel K <skevetter@pm.me>
@coderabbitai
Copy link

coderabbitai bot commented Feb 4, 2026

📝 Walkthrough

Walkthrough

Refactors workspace init to use parameter structs; consolidates provider types to the public provider package; moves binary/env handling to provider-managed APIs with retries and checksum validation; adds download.HTTPStatusError; updates many function signatures and client/driver call sites accordingly.

Changes

Cohort / File(s) Summary
Agent workspace init & commands
cmd/agent/workspace/build.go, cmd/agent/workspace/up.go
Refactored initWorkspace to accept initWorkspaceParams; replaced provider2 types with provider.AgentWorkspaceInfo; restructured initialization into workspaceInitializer and modular helpers for credentials, daemon, content, and binary downloads; adjusted logging and return values.
Provider binary/download core
pkg/provider/download.go, pkg/download/download.go
Introduced ProviderBinary/ProviderConfig usage, retry/backoff logic, checksum verification/cleanup, cache path changes, and added exported download.HTTPStatusError for non-2xx responses; switched to filepath joins and improved error context.
Options resolution & provider consolidation
pkg/options/resolve.go, pkg/workspace/provider.go
Replaced legacy aliases (provider2/providerpkg) with unified provider types across public APIs; added agent config resolution helpers and harmonized provider loading/saving and provider-source resolution flows.
Client implementations (workspace/options)
pkg/client/clientimplementation/workspace_client.go, pkg/client/clientimplementation/daemonclient/client.go, pkg/client/clientimplementation/proxy_client.go
Removed direct binaries dependency in workspace client, added workspaceClient.buildEnvironment; switched options resolution calls to ResolveAndSaveOptionsWorkspace with resolver.WithResolveSubOptions(); adjusted ping/context cancel semantics.
Drivers and environment builders
pkg/driver/custom/custom.go
Updated driver constructor and environment functions to accept *provider.AgentWorkspaceInfo; replaced binaries calls with provider.DownloadBinaries / provider.ToEnvironment.
Workspace creation & tests
pkg/workspace/workspace.go, e2e/tests/integration/integration.go
Added RemoteCreator interface and parameterized pro-instance resolution; updated workspace creation flow to use stream-aware Create; refactored e2e tests to be context-aware and use filepath helpers.
CI workflow
.github/workflows/pr-ci.yml
Reduced Go test timeout from 3600s to 900s for PR CI jobs.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.51% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'refactor move binaries to provider' clearly summarizes the main change: refactoring binaries into the provider package, which is the primary focus reflected across file changes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor-move-binaries-to-provider

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 and usage tips.

Signed-off-by: Samuel K <skevetter@pm.me>
Signed-off-by: Samuel K <skevetter@pm.me>
Signed-off-by: Samuel K <skevetter@pm.me>
Signed-off-by: Samuel K <skevetter@pm.me>
@skevetter skevetter marked this pull request as ready for review February 4, 2026 20:56
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

⚠️ Outside diff range comments (3)
pkg/download/download.go (2)

30-41: ⚠️ Potential issue | 🟡 Minor

Close the HEAD response body to avoid leaking connections.
Line 36 returns the status without closing resp.Body, which can exhaust the HTTP client’s connection pool over time.

🛠️ Suggested fix
 resp, err := devpodhttp.GetHTTPClient().Do(req)
 if err != nil {
 	return 0, fmt.Errorf("download file: %w", err)
 }
+defer resp.Body.Close()

 return resp.StatusCode, nil

108-123: ⚠️ Potential issue | 🟡 Minor

Ensure the release metadata response body is closed.
Line 125 reads the body but it’s never closed; this can leak connections on repeated calls.

🛠️ Suggested fix
 resp, err := devpodhttp.GetHTTPClient().Do(req)
 if err != nil {
 	return nil, err
 } else if resp.StatusCode >= 400 {
 	_ = resp.Body.Close()
 	return nil, &HTTPStatusError{
 		StatusCode: resp.StatusCode,
 		URL:        releaseURL,
 	}
 }
+defer resp.Body.Close()

 raw, err := io.ReadAll(resp.Body)
pkg/client/clientimplementation/workspace_client.go (1)

509-524: ⚠️ Potential issue | 🟠 Major

Unlock on error to avoid deadlocks.
If provider.ToEnvironmentWithBinaries fails, Line 521 returns before s.m.Unlock() runs, leaving the mutex locked.

🛠️ Suggested fix
 s.m.Lock()
 environ, err := provider.ToEnvironmentWithBinaries(provider.EnvironmentOptions{
 	Context:   s.workspace.Context,
 	Workspace: s.workspace,
 	Machine:   s.machine,
 	Options:   s.devPodConfig.ProviderOptions(s.config.Name),
 	Config:    s.config,
 	ExtraEnv: map[string]string{
 		provider.CommandEnv: commandOptions.Command,
 	},
 	Log: s.log,
 })
 if err != nil {
+	s.m.Unlock()
 	return err
 }
 s.m.Unlock()

Signed-off-by: Samuel K <skevetter@pm.me>
Signed-off-by: Samuel K <skevetter@pm.me>
@skevetter skevetter marked this pull request as draft February 5, 2026 01:55
@github-actions
Copy link

github-actions bot commented Feb 5, 2026

⚠️ This PR contains unsigned commits. To get your PR merged, please sign those commits (git rebase --exec 'git commit -S --amend --no-edit -n' @{upstream}) and force push them to this branch (git push --force-with-lease).

If you're new to commit signing, there are different ways to set it up:

Sign commits with gpg

Follow the steps below to set up commit signing with gpg:

  1. Generate a GPG key
  2. Add the GPG key to your GitHub account
  3. Configure git to use your GPG key for commit signing
Sign commits with ssh-agent

Follow the steps below to set up commit signing with ssh-agent:

  1. Generate an SSH key and add it to ssh-agent
  2. Add the SSH key to your GitHub account
  3. Configure git to use your SSH key for commit signing
Sign commits with 1Password

You can also sign commits using 1Password, which lets you sign commits with biometrics without the signing key leaving the local 1Password process.

Learn how to use 1Password to sign your commits.

Watch the demo

Signed-off-by: Samuel K <skevetter@pm.me>
Signed-off-by: Samuel K <skevetter@pm.me>
@skevetter skevetter force-pushed the refactor-move-binaries-to-provider branch from 1e47f88 to ff38e0b Compare February 5, 2026 03:22
Signed-off-by: Samuel K <skevetter@pm.me>
@skevetter skevetter marked this pull request as ready for review February 5, 2026 04:17
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

⚠️ Outside diff range comments (3)
e2e/tests/integration/integration.go (1)

62-65: ⚠️ Potential issue | 🟡 Minor

Use the already-defined authorizedKeysPath variable for consistency.

Line 63 constructs the path using string concatenation while authorizedKeysPath (defined at line 57) was already created using filepath.Join for cross-platform compatibility. This inconsistency could cause issues on non-Unix systems.

🛠️ Proposed fix
 			} else {
-				f, err := os.OpenFile(os.Getenv("HOME")+"/.ssh/authorized_keys",
+				f, err := os.OpenFile(authorizedKeysPath,
 					os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
 				framework.ExpectNoError(err)
pkg/options/resolve.go (2)

20-154: ⚠️ Potential issue | 🟡 Minor

Expand nil validation to providerConfig/devConfig.
These functions dereference providerConfig.Name and devConfig.DefaultContext; if callers ever pass nil, this will panic. You already guard originalMachine/originalWorkspace, so consider guarding providerConfig/devConfig similarly.

🛡️ Proposed guard (apply in both functions)
 func ResolveAndSaveOptionsMachine(
     ctx context.Context,
     devConfig *config.Config,
     providerConfig *provider.ProviderConfig,
     originalMachine *provider.Machine,
     userOptions map[string]string,
     log log.Logger,
 ) (*provider.Machine, error) {
     if originalMachine == nil {
         return nil, fmt.Errorf("originalMachine cannot be nil")
     }
+    if providerConfig == nil || devConfig == nil {
+        return nil, fmt.Errorf("providerConfig and devConfig cannot be nil")
+    }
 func ResolveAndSaveOptionsWorkspace(
     ctx context.Context,
     devConfig *config.Config,
     providerConfig *provider.ProviderConfig,
     originalWorkspace *provider.Workspace,
     userOptions map[string]string,
     log log.Logger,
     options ...resolver.Option,
 ) (*provider.Workspace, error) {
     if originalWorkspace == nil {
         return nil, fmt.Errorf("originalWorkspace cannot be nil")
     }
+    if providerConfig == nil || devConfig == nil {
+        return nil, fmt.Errorf("providerConfig and devConfig cannot be nil")
+    }

157-221: ⚠️ Potential issue | 🟡 Minor

Guard ResolveOptions against nil providerConfig/devConfig or document the non-nil contract.
ResolveOptions uses devConfig.DefaultContext and providerConfig.Name before any nil checks. If nil can occur, return a clear error; if not, consider documenting it.

🛡️ Proposed guard
 func ResolveOptions(
     ctx context.Context,
     devConfig *config.Config,
     providerConfig *provider.ProviderConfig,
     userOptions map[string]string,
     skipRequired bool,
     skipSubOptions bool,
     singleMachine *bool,
     log log.Logger,
 ) (*config.Config, error) {
+    if providerConfig == nil || devConfig == nil {
+        return nil, fmt.Errorf("providerConfig and devConfig cannot be nil")
+    }
     // get binary paths
     binaryPaths, err := provider.GetBinaries(devConfig.DefaultContext, providerConfig)
🧹 Nitpick comments (1)
pkg/provider/download.go (1)

196-211: Consider whether all net.OpError cases should be retriable.

Currently, all net.OpError instances are marked as retriable (line 203). While connection errors often benefit from retries, some net.OpError cases like "address already in use" or permission errors may not be transient. Consider checking opErr.Temporary() or opErr.Timeout() for more precise classification.

♻️ Suggested refinement
 	var opErr *net.OpError
 	if errors.As(err, &opErr) {
-		return true
+		return opErr.Temporary() || opErr.Timeout()
 	}

@skevetter skevetter merged commit 97754be into main Feb 5, 2026
39 checks passed
@skevetter skevetter deleted the refactor-move-binaries-to-provider branch February 5, 2026 04:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant