Skip to content

fix: GPG agent forwarding crash with SSH signing keys (#731)#732

Merged
skevetter merged 6 commits intomainfrom
investigate-issue-731
Apr 14, 2026
Merged

fix: GPG agent forwarding crash with SSH signing keys (#731)#732
skevetter merged 6 commits intomainfrom
investigate-issue-731

Conversation

@skevetter
Copy link
Copy Markdown
Owner

@skevetter skevetter commented Apr 13, 2026

  • Skip passing --gitkey to setup-gpg when gpg.format = ssh, since SSH signing keys are handled by the separate SSH signature helper path
  • Make signing key setup non-fatal in setup-gpg so a failure doesn't tear down the entire tunnel and kill the SSH server
  • Add E2E test reproducing the scenario from [Bug]: Starting project with gpg agent forwarding fails to start the ssh server #731: SSH signing configured + GPG forwarding enabled

Fixes #731

Summary by CodeRabbit

  • Bug Fixes

    • GPG setup is more resilient: failures when configuring a git signing key are logged as warnings and no longer abort workspace startup.
  • Tests

    • Added unit tests covering signing-key detection across formats and configurations.
    • Added an end-to-end test validating GPG agent forwarding with SSH signing format.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 13, 2026

Warning

Rate limit exceeded

@skevetter has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 6 minutes and 58 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 6 minutes and 58 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d34c6bfe-43bb-4927-801c-0b3e126b0b17

📥 Commits

Reviewing files that changed from the base of the PR and between ee0d75e and f885098.

📒 Files selected for processing (1)
  • e2e/tests/ssh/ssh.go
📝 Walkthrough

Walkthrough

Refactors GPG/git signing-key detection into a helper and makes git signing-key setup non-fatal during agent workspace setup; adds unit tests for signing-key detection and an e2e test for GPG agent forwarding with SSH-format signing keys.

Changes

Cohort / File(s) Summary
GPG Agent Workspace Setup
cmd/agent/workspace/setup_gpg.go
Change: treat failures from git signing-key setup as warnings (log only) instead of returning an error, allowing Run to continue.
SSH/GPG Signing Key Detection
cmd/ssh.go
Change: extracted gpgSigningKey(log) to determine git signing key via gpg.format and user.signingKey; setupGPGAgent now conditionally appends --gitkey when non-empty.
Unit Tests for Signing Key Detection
cmd/ssh_test.go
Added: writeGitConfig() helper and four tests validating gpgSigningKey() for GPG format, SSH format (skipped), missing key, and X509 format.
End-to-End SSH/GPG Test
e2e/tests/ssh/ssh.go
Added: new e2e test (non-Windows) that provisions a workspace with --gpg-agent-forwarding, generates an SSH key, writes a temporary global .gitconfig with gpg.format = ssh and user.signingKey, and verifies SSH connectivity.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

size/l

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% 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 clearly summarizes the main fix: handling GPG agent forwarding when SSH signing keys are in use, which directly addresses the crash described in issue #731.
Linked Issues check ✅ Passed All three coding objectives from #731 are met: (1) --gitkey not passed for SSH format [cmd/ssh.go], (2) signing key setup made non-fatal [cmd/agent/workspace/setup_gpg.go], (3) E2E test added [e2e/tests/ssh/ssh.go].
Out of Scope Changes check ✅ Passed All changes are directly scoped to fix #731: refactoring GPG key detection logic, making it handle SSH keys properly, adding unit and E2E tests; no unrelated changes present.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch investigate-issue-731

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.

@github-actions
Copy link
Copy Markdown

⚠️ 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

@skevetter skevetter force-pushed the investigate-issue-731 branch from c6b235a to 1c85086 Compare April 13, 2026 14:50
@github-actions github-actions bot added size/l and removed size/m labels Apr 13, 2026
@skevetter skevetter force-pushed the investigate-issue-731 branch from 1c85086 to 07eff03 Compare April 13, 2026 16:58
@github-actions github-actions bot added size/m and removed size/l labels Apr 13, 2026
When the user has SSH-based commit signing configured (gpg.format=ssh),
the GPG agent forwarding code no longer passes the SSH key path as
--gitkey to setup-gpg. SSH signing keys are handled by the separate
SSH signature helper path.
Setting user.signingKey in the container is optional — if it fails,
GPG agent forwarding and the SSH server should still start. This
prevents a bad signing key configuration from tearing down the
entire tunnel.
Validates that workspace starts successfully when GPG agent forwarding
is enabled and the host has gpg.format=ssh with an SSH signing key.
This is the exact scenario reported in issue #731.
@skevetter skevetter force-pushed the investigate-issue-731 branch from 07eff03 to 52edd73 Compare April 13, 2026 18:51
@skevetter skevetter marked this pull request as ready for review April 13, 2026 22:19
@skevetter
Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 13, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai bot added the size/l label Apr 13, 2026
Copy link
Copy Markdown

@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.

🧹 Nitpick comments (1)
e2e/tests/ssh/ssh.go (1)

88-90: Consider using ginkgo.DeferCleanup for consistent cleanup patterns.

The test uses defer os.RemoveAll for sshKeyDir but ginkgo.GinkgoT().TempDir() for gitConfigDir. For consistency with the workspace cleanup pattern (lines 81-84) and better integration with Ginkgo's lifecycle, consider using DeferCleanup:

♻️ Suggested refactor for consistent cleanup
 			sshKeyDir, err := os.MkdirTemp("", "devpod-gpg-ssh-test")
 			framework.ExpectNoError(err)
-			defer func() { _ = os.RemoveAll(sshKeyDir) }()
+			ginkgo.DeferCleanup(func() { _ = os.RemoveAll(sshKeyDir) })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/tests/ssh/ssh.go` around lines 88 - 90, The test creates sshKeyDir via
os.MkdirTemp and uses defer os.RemoveAll for cleanup; replace that defer with a
ginkgo.DeferCleanup call so cleanup participates in Ginkgo's lifecycle. After
creating sshKeyDir (the variable assigned by os.MkdirTemp and validated by
framework.ExpectNoError), call ginkgo.DeferCleanup with either a closure that
calls os.RemoveAll(sshKeyDir) or DeferCleanup(os.RemoveAll, sshKeyDir) to mirror
the gitConfigDir pattern and ensure consistent cleanup.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@e2e/tests/ssh/ssh.go`:
- Around line 88-90: The test creates sshKeyDir via os.MkdirTemp and uses defer
os.RemoveAll for cleanup; replace that defer with a ginkgo.DeferCleanup call so
cleanup participates in Ginkgo's lifecycle. After creating sshKeyDir (the
variable assigned by os.MkdirTemp and validated by framework.ExpectNoError),
call ginkgo.DeferCleanup with either a closure that calls
os.RemoveAll(sshKeyDir) or DeferCleanup(os.RemoveAll, sshKeyDir) to mirror the
gitConfigDir pattern and ensure consistent cleanup.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 64be66fb-7fed-4237-a582-961e01631a88

📥 Commits

Reviewing files that changed from the base of the PR and between 92659e6 and 52edd73.

📒 Files selected for processing (4)
  • cmd/agent/workspace/setup_gpg.go
  • cmd/ssh.go
  • cmd/ssh_test.go
  • e2e/tests/ssh/ssh.go

@github-actions github-actions bot removed the size/l label Apr 13, 2026
@coderabbitai coderabbitai bot added the size/l label Apr 14, 2026
Copy link
Copy Markdown

@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.

🧹 Nitpick comments (1)
e2e/tests/ssh/ssh.go (1)

64-114: Well-structured test that correctly verifies the fix for issue #731.

The test appropriately:

  • Skips on Windows where GPG forwarding behavior differs.
  • Sets up an isolated environment with a temporary SSH key and git config.
  • Configures gpg.format = ssh to trigger the code path that previously caused the crash.
  • Verifies SSH connectivity works after DevPodUp with --gpg-agent-forwarding.

One minor inconsistency: you use os.MkdirTemp (line 86) with explicit DeferCleanup for the SSH key directory, but GinkgoT().TempDir() (line 97) for the git config directory (which auto-cleans). Consider using GinkgoT().TempDir() consistently for both to simplify cleanup handling.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/tests/ssh/ssh.go` around lines 64 - 114, The test mixes os.MkdirTemp
(sshKeyDir) with ginkgo.GinkgoT().TempDir() (gitConfigDir); switch sshKeyDir
creation to ginkgo.GinkgoT().TempDir() instead of os.MkdirTemp, remove the
explicit ginkgo.DeferCleanup that calls os.RemoveAll(sshKeyDir), and keep the
rest of the logic (keyPath, ssh-keygen call, and git config handling) unchanged
so cleanup is consistently managed by GinkgoT().TempDir(); update references to
sshKeyDir, os.MkdirTemp, ginkgo.GinkgoT().TempDir(), ginkgo.DeferCleanup, and
os.RemoveAll accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@e2e/tests/ssh/ssh.go`:
- Around line 64-114: The test mixes os.MkdirTemp (sshKeyDir) with
ginkgo.GinkgoT().TempDir() (gitConfigDir); switch sshKeyDir creation to
ginkgo.GinkgoT().TempDir() instead of os.MkdirTemp, remove the explicit
ginkgo.DeferCleanup that calls os.RemoveAll(sshKeyDir), and keep the rest of the
logic (keyPath, ssh-keygen call, and git config handling) unchanged so cleanup
is consistently managed by GinkgoT().TempDir(); update references to sshKeyDir,
os.MkdirTemp, ginkgo.GinkgoT().TempDir(), ginkgo.DeferCleanup, and os.RemoveAll
accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8ee99ac1-ad6c-451a-a347-32fa42cf5547

📥 Commits

Reviewing files that changed from the base of the PR and between 52edd73 and ee0d75e.

📒 Files selected for processing (1)
  • e2e/tests/ssh/ssh.go

@skevetter skevetter marked this pull request as draft April 14, 2026 00:28
@github-actions github-actions bot removed the size/l label Apr 14, 2026
@skevetter skevetter marked this pull request as ready for review April 14, 2026 01:14
@skevetter skevetter merged commit fdd4906 into main Apr 14, 2026
41 checks passed
@skevetter skevetter deleted the investigate-issue-731 branch April 14, 2026 01:30
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.

[Bug]: Starting project with gpg agent forwarding fails to start the ssh server

1 participant