Skip to content

fix(runpod): make new pods accept the configured SSH key - #1203

Merged
steipete merged 2 commits into
openclaw:mainfrom
morluto:fix/runpod-public-key
Jul 31, 2026
Merged

fix(runpod): make new pods accept the configured SSH key#1203
steipete merged 2 commits into
openclaw:mainfrom
morluto:fix/runpod-public-key

Conversation

@morluto

@morluto morluto commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Closes #1202

What Problem This Solves

Fixes an issue where users provisioning RunPod leases with a configured ssh.key would receive a running pod with an exposed SSH port but no matching authorized key. The pod could report PUBLIC_KEY as null, leaving Crabbox's SSH readiness check unable to authenticate.

Why This Change Was Made

The RunPod provider now reads the configured key's adjacent .pub file before creating the pod and serializes that exact value as env.PUBLIC_KEY in the POST /pods request. Missing or empty public-key files fail before the paid resource is created.

This keeps key ownership unchanged: the private key remains local, and only its public half is included in the provider request.

ssh.key.pub
    |
    v
RunPod POST /pods
  env.PUBLIC_KEY
    |
    v
official image startup -> ~/.ssh/authorized_keys -> sshd

User Impact

RunPod pods created by Crabbox can authorize the same SSH identity that Crabbox uses for readiness, sync, and command execution. Invalid local key configuration now fails before pod creation instead of producing an unreachable running lease.

Evidence

  • Two Crabbox 0.38.0 provisioning attempts reached RUNNING with public port 22 but could not authenticate; the pod environment showed PUBLIC_KEY as null.
  • The regression test proves the configured .pub value reaches the acquire request and JSON serialization preserves it as env.PUBLIC_KEY.
  • go test ./internal/providers/runpod -count=1 — pass.
  • go test -race ./internal/providers/runpod ./internal/providers/all -count=1 — pass.
  • go vet ./internal/providers/runpod ./internal/providers/all — pass.
  • go build -trimpath -o /tmp/crabbox-runpod-key-check ./cmd/crabbox — pass.

Live provider proof

Validated commit 1a3b1aabb466ef48bcbf46b500de9e6d594e1037 with the patched Crabbox binary and a disposable SSH key created only for this test.

The one-shot RunPod lease completed SSH readiness, repository sync, and a remote command:

provider=runpod
lease_id=cbx_929b8e20f493
remote_command=CRABBOX_PR1203_LIVE_OK
exit_status=0
run_status=succeeded
lease_stopped=true
post_run_pod_count=0

The missing-sidecar preflight was also exercised with the disposable public-key file temporarily absent:

exit_status=2
error=read SSH public key <redacted-path>.pub: no such file or directory
post_attempt_pod_count=0

The private key remained local. The evidence above omits the disposable key value, API credentials, host/IP, port, local paths, and provider endpoints. RunPod reported no remaining pods after either check.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. labels Jul 28, 2026
@clawsweeper

clawsweeper Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs changes before merge. Reviewed July 31, 2026, 11:22 AM ET / 15:22 UTC.

ClawSweeper review

What this changes

The PR loads the configured SSH key’s adjacent public-key file, validates it before deployment, and places it in RunPod’s pod environment as PUBLIC_KEY so the pod authorizes Crabbox’s SSH identity.

Merge readiness

⚠️ Needs maintainer review before merge - 3 items remain

Keep this PR open: it has strong redacted live RunPod proof and a focused fix for the linked SSH-authentication bug, but the current shared validator still accepts malformed OpenSSH key payloads and can therefore create a paid pod that cannot authorize Crabbox’s identity.

Priority: P2
Reviewed head: 6df3811bd8feef484dbe85e731b43f8fa71abe19

Review scores

Measure Result What it means
Overall readiness 🦐 gold shrimp (3/6) Strong real provider evidence supports the main fix, but the shared key validator has a definite malformed-input hole that blocks merge.
Proof confidence 🦞 diamond lobster (5/6) Sufficient (live_output): The PR body provides redacted after-fix RunPod output showing SSH readiness, repository sync, remote command success, cleanup, and a missing-public-key preflight that left no pod behind.
Patch quality 🦐 gold shrimp (3/6) 1 actionable review finding remain.

Verification

Check Result Evidence
Real behavior Verified Sufficient (live_output): The PR body provides redacted after-fix RunPod output showing SSH readiness, repository sync, remote command success, cleanup, and a missing-public-key preflight that left no pod behind.
Evidence reviewed 4 items PR live-provider proof: The PR body reports a disposable-key RunPod lease that completed SSH readiness, repository sync, a remote command, and cleanup; it also reports a missing-sidecar preflight that created no pod.
Unresolved current-head validation defect: The supplied current-head diff shows that LooksLikeInlineSSHPublicKey accepts every supported key type with any nonempty second field. A value such as ssh-ed25519 not-base64 passes validation, is placed into PUBLIC_KEY, and can still result in an unauthorizable paid pod. The prior completed review cycle identified this same blocker on unchanged head 6df3811bd8feef484dbe85e731b43f8fa71abe19.
Maintainer follow-up provenance: The provided PR history shows that the shared key-loading and validation path was introduced by a maintainer follow-up commit, which also moved the RunPod behavior onto the shared helper.
Findings 1 actionable finding [P2] Parse the complete OpenSSH public key before deployment
Security None None.

How this fits together

Crabbox converts a lease configuration into a RunPod pod request, then uses the configured local SSH identity for readiness, repository sync, and remote commands. The provider request must receive a valid matching public key so the remote image can add it to authorized_keys before Crabbox connects.

flowchart LR
  Config[Lease configuration] --> KeyPath[Configured SSH key path]
  KeyPath --> PublicKey[Adjacent public-key file]
  PublicKey --> Validation[OpenSSH key validation]
  Validation --> PodRequest[RunPod pod request]
  PodRequest --> PodEnv[PUBLIC_KEY environment]
  PodEnv --> SSHAccess[SSH readiness, sync, and commands]
Loading

Before merge

  • Parse the complete OpenSSH public key before deployment (P2) - LooksLikeInlineSSHPublicKey only checks a supported type plus a nonempty second field, so malformed values such as ssh-ed25519 not-base64 pass the new preflight and are sent to RunPod. The pod can then be created but reject Crabbox’s SSH identity, defeating the fail-before-paid-deployment guarantee. This remains the prior blocker on unchanged head.
  • Resolve merge risk (P1) - Existing users with malformed but nonempty .pub files can pass the new preflight and still pay for a RunPod pod that rejects the configured identity, replacing an immediate actionable validation failure with a failed remote workflow.
  • Resolve merge risk (P1) - The branch also edits release-owned CHANGELOG.md; repository policy says normal PRs should not make that edit, although this is not the functional blocker.

Findings

  • [P2] Parse the complete OpenSSH public key before deployment — internal/cli/lease.go:57-70
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Patch surface 8 files changed; 170 additions, 24 deletions The main provider fix is focused, but shared CLI and KubeVirt validation reuse make the parser contract cross-provider.
Live provider proof 1 successful disposable-key lease plus 1 no-pod preflight check The supplied redacted output directly demonstrates the intended RunPod behavior and cleanup path.

Merge-risk options

Maintainer options:

  1. Harden public-key parsing before merge (recommended)
    Replace the type-and-token heuristic with complete OpenSSH authorized-key parsing, add a malformed-payload regression test, and keep valid configured keys unchanged.
  2. Accept the validation gap
    Merge with the current heuristic only if maintainers accept that malformed local .pub files may still create unusable paid pods.
  3. Pause the branch
    Pause this branch if the intended SSH-key compatibility contract needs a broader policy decision beyond strict OpenSSH parsing.
Copy recommended automerge instruction
@clawsweeper automerge

Special instructions:
Use a complete OpenSSH authorized-key parser in the shared helper; add coverage proving malformed base64 or otherwise invalid payloads fail before RunPod deployment, and remove the release-owned changelog edit.

Technical review

Best possible solution:

Use a complete authorized-key parser for the shared helper, add malformed-payload coverage, preserve the exact validated public key in the RunPod request, and remove the release-owned changelog entry before merge.

Do we have a high-confidence way to reproduce the issue?

Yes, source-reproducible with high confidence: provide a configured .pub file containing a supported type and an invalid nonempty payload such as ssh-ed25519 not-base64; the current predicate accepts it and the RunPod path sends it as PUBLIC_KEY. The supplied live provider run also demonstrates the intended valid-key behavior after the underlying deployment fix.

Is this the best way to solve the issue?

No, not yet: serializing the configured key is the correct narrow repair, but the current type-and-token heuristic does not prove a complete OpenSSH authorized key and fails the stated preflight guarantee. A standard authorized-key parser is the safer shared-core solution.

Full review comments:

  • [P2] Parse the complete OpenSSH public key before deployment — internal/cli/lease.go:57-70
    LooksLikeInlineSSHPublicKey only checks a supported type plus a nonempty second field, so malformed values such as ssh-ed25519 not-base64 pass the new preflight and are sent to RunPod. The pod can then be created but reject Crabbox’s SSH identity, defeating the fail-before-paid-deployment guarantee. This remains the prior blocker on unchanged head.
    Confidence: 0.98

Overall correctness: patch is incorrect
Overall confidence: 0.98

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 5aa1c3983874.

Labels

Label changes:

  • add merge-risk: 🚨 auth-provider: The change controls the SSH identity delivered to RunPod and whether Crabbox can authenticate to newly created pods.

Label justifications:

  • P2: This is a bounded provider regression that can make RunPod leases unusable and consume paid provisioning time, but does not indicate an emergency-wide outage.
  • merge-risk: 🚨 compatibility: The shared validator changes acceptance of existing configured .pub files and must reject malformed inputs without breaking valid OpenSSH key formats.
  • merge-risk: 🚨 auth-provider: The change controls the SSH identity delivered to RunPod and whether Crabbox can authenticate to newly created pods.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦞 diamond lobster and patch quality is 🦐 gold shrimp.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (live_output): The PR body provides redacted after-fix RunPod output showing SSH readiness, repository sync, remote command success, cleanup, and a missing-public-key preflight that left no pod behind.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body provides redacted after-fix RunPod output showing SSH readiness, repository sync, remote command success, cleanup, and a missing-public-key preflight that left no pod behind.

Evidence

Acceptance criteria:

  • [P1] go test ./internal/cli ./internal/providers/runpod ./internal/providers/kubevirt -count=1.
  • [P1] go vet ./internal/cli ./internal/providers/runpod ./internal/providers/kubevirt.

What I checked:

  • PR live-provider proof: The PR body reports a disposable-key RunPod lease that completed SSH readiness, repository sync, a remote command, and cleanup; it also reports a missing-sidecar preflight that created no pod. (internal/providers/runpod/backend.go:89, 1a3b1aabb466)
  • Unresolved current-head validation defect: The supplied current-head diff shows that LooksLikeInlineSSHPublicKey accepts every supported key type with any nonempty second field. A value such as ssh-ed25519 not-base64 passes validation, is placed into PUBLIC_KEY, and can still result in an unauthorizable paid pod. The prior completed review cycle identified this same blocker on unchanged head 6df3811bd8feef484dbe85e731b43f8fa71abe19. (internal/cli/lease.go:55, 6df3811bd8fe)
  • Maintainer follow-up provenance: The provided PR history shows that the shared key-loading and validation path was introduced by a maintainer follow-up commit, which also moved the RunPod behavior onto the shared helper. (internal/cli/lease.go:30, 6df3811bd8fe)
  • Local inspection unavailable: The required read-only shell inspection could not start because the sandbox failed with bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted; this review therefore relies on the supplied complete GitHub context and diff rather than claiming local current-main or history inspection.

Likely related people:

  • steipete: The supplied PR history attributes the shared SSH public-key validation follow-up to this commit, and the maintainer comment describes moving validation into the core helper. (role: recent area contributor; confidence: high; commits: 6df3811bd8fe; files: internal/cli/lease.go, internal/providers/runpod/backend.go, internal/providers/kubevirt/backend.go)
  • morluto: The supplied PR history attributes the RunPod deployment payload fix and live provider validation to this commit. (role: original RunPod fix contributor; confidence: high; commits: 1a3b1aabb466; files: internal/providers/runpod/backend.go, internal/providers/runpod/client.go, internal/providers/runpod/backend_test.go)

Rank-up moves

Optional improvements that raise the rating; they are not merge blockers.

  • Replace the heuristic with complete OpenSSH authorized-key parsing.
  • Add a regression case for a supported key type with invalid key payload data.
  • Remove the release-owned CHANGELOG.md entry.

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (10 earlier review cycles; latest 8 shown)
  • reviewed 2026-07-29T15:41:14.611Z sha 6df3811 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-30T01:13:52.173Z sha 6df3811 :: needs changes before merge. :: [P3] Remove the release-owned changelog entry
  • reviewed 2026-07-30T01:27:54.110Z sha 6df3811 :: needs changes before merge. :: [P3] Remove the release-owned changelog entry
  • reviewed 2026-07-30T11:52:24.724Z sha 6df3811 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-30T13:38:17.944Z sha 6df3811 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-30T18:26:23.656Z sha 6df3811 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-31T02:54:32.103Z sha 6df3811 :: needs changes before merge. :: [P2] Parse the complete OpenSSH public key before deployment
  • reviewed 2026-07-31T06:31:21.572Z sha 6df3811 :: needs changes before merge. :: [P2] Parse the complete OpenSSH public key before deployment

@morluto

morluto commented Jul 28, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

Re-review progress:

@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jul 28, 2026
@steipete

Copy link
Copy Markdown
Contributor

Thanks, @morluto — I pushed a small maintainer follow-up on top of your commit.

I moved adjacent public-key loading and validation into the shared core helper, reused the existing OpenSSH type guard from KubeVirt, added a clear error for an unconfigured key path, and covered missing, empty, and private-key-content .pub files with zero-deploy assertions. This keeps your RunPod fix focused while ensuring bad key material is rejected before a paid pod is created.

Your redacted live RunPod proof—successful SSH, sync, and command execution plus zero pods after the missing-sidecar failure—was the deciding evidence for moving this forward. Thank you for doing that careful validation.

@steipete
steipete enabled auto-merge (squash) July 29, 2026 17:01
@clawsweeper clawsweeper Bot added rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jul 30, 2026
@steipete
steipete merged commit f793138 into openclaw:main Jul 31, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P2 Normal priority bug or improvement with limited blast radius. proof: sufficient Contributor real behavior proof is sufficient. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RunPod pods cannot authenticate with the configured SSH key

2 participants