Skip to content

Add GitHub Codespaces as a Crabbox Linux provider #348

@coygeek

Description

@coygeek

Add GitHub Codespaces as a Crabbox Linux provider

Summary

Add a first-party github-codespaces provider for Crabbox so users can acquire
short-lived Linux leases backed by GitHub Codespaces, run normal Crabbox
repo-sync and command workflows, then stop or delete the codespace safely.

The best Phase 1 shape is an SSH-lease provider that relies on GitHub's
supported Codespaces access path:

  • use the GitHub Codespaces REST API or gh codespace JSON commands for
    create/list/view/start/stop/delete;
  • use gh codespace ssh --config or an equivalent gh-mediated OpenSSH config
    to expose the codespace as a normal OpenSSH target;
  • let Crabbox core own sync, command execution, ssh, status rendering, local
    claims, and release once a usable SSH target is available.

This is not a brokered coordinator provider in the first implementation.
Codespaces are owned by the authenticated GitHub user or billed organization,
and the direct CLI should reuse the operator's existing gh authentication or a
GitHub token with Codespaces access.

Motivation

GitHub Codespaces is a strong missing Crabbox target:

  • It is already tied to a GitHub repository, branch, devcontainer, machine type,
    idle timeout, and retention period, which matches Crabbox's short-lived
    repo-workflow use case.
  • GitHub exposes a Codespaces REST surface for create/list/get/update/delete,
    start/stop, repository defaults, permission checks, and machine type discovery.
  • GitHub CLI exposes the operational pieces Crabbox needs locally: gh codespace create, list --json, view --json, ssh --config, cp,
    ports, stop, and delete.
  • If a codespace has an SSH server installed, gh codespace ssh --config can
    generate OpenSSH configuration, letting Crabbox reuse its existing SSH/sync/run
    machinery instead of inventing a new remote execution protocol.

The main risk is that Codespaces is not a raw VM API. The public REST object does
not hand back a normal host, port, username, and private key. Crabbox should
treat the GitHub CLI/OpenSSH integration as the supported connection layer and
fail clearly when the selected devcontainer image does not include an SSH server.

Recommended phase 1 scope

Implement provider: github-codespaces as a Linux-only, direct-only SSH lease
provider.

Provider spec:

Name:        github-codespaces
Aliases:     codespaces, gh-codespaces
Family:      github-codespaces
Kind:        ssh-lease
Targets:     linux
Features:    ssh, crabbox-sync, cleanup
Coordinator: never

Phase 1 should support:

  • crabbox warmup --provider github-codespaces
  • crabbox run --provider github-codespaces -- <command>
  • crabbox ssh --provider github-codespaces --id <lease-or-slug>
  • crabbox list --provider github-codespaces --json
  • crabbox status --provider github-codespaces --id <lease-or-slug> --json
  • crabbox stop --provider github-codespaces <lease-or-slug>
  • crabbox cleanup --provider github-codespaces --dry-run
  • crabbox doctor --provider github-codespaces

Phase 1 should not attempt Windows, macOS, VNC/desktop/browser/code-server,
coordinator brokerage, GitHub organization admin listing, Codespaces secrets
management, prebuild management, port visibility management, or unpublished
codespace export/publish flows.

GitHub API and CLI fit

The local GitHub docs and live official docs show the lifecycle operations
Crabbox needs:

  • POST /repos/{owner}/{repo}/codespaces creates a repository codespace.
  • POST /repos/{owner}/{repo}/pulls/{pull_number}/codespaces creates a
    codespace from a pull request.
  • GET /repos/{owner}/{repo}/codespaces lists repository codespaces for the
    authenticated user.
  • GET /user/codespaces lists the authenticated user's codespaces.
  • GET /user/codespaces/{codespace_name} gets one codespace.
  • PATCH /user/codespaces/{codespace_name} updates machine/display metadata.
  • POST /user/codespaces/{codespace_name}/start starts a codespace.
  • POST /user/codespaces/{codespace_name}/stop stops a codespace.
  • DELETE /user/codespaces/{codespace_name} deletes a codespace.
  • GET /repos/{owner}/{repo}/codespaces/new gets default attributes.
  • GET /repos/{owner}/{repo}/codespaces/permissions_check checks whether
    devcontainer permissions have been accepted.
  • GET /repos/{owner}/{repo}/codespaces/machines lists repository machine
    types.
  • GET /user/codespaces/{codespace_name}/machines lists alternate machine
    types for an existing codespace.

Useful create request fields include:

  • ref
  • geo or legacy location
  • machine
  • devcontainer_path
  • multi_repo_permissions_opt_out
  • working_directory
  • idle_timeout_minutes
  • display_name
  • retention_period_minutes

Useful codespace response fields include:

  • name
  • display_name
  • environment_id
  • state
  • machine
  • repository
  • location
  • idle_timeout_minutes
  • web_url
  • machines_url
  • start_url
  • stop_url
  • retention_period_minutes
  • retention_expires_at
  • pending operation fields

GitHub CLI help adds the most important SSH details:

  • gh codespace ssh --config writes OpenSSH config for codespaces.
  • Once included in ~/.ssh/config, ordinary ssh, scp, rsync, and related
    OpenSSH tools can target codespaces.
  • gh codespace ssh automatically manages a local SSH key if needed.
  • The codespace image must have an SSH server installed. The CLI docs recommend
    adding the ghcr.io/devcontainers/features/sshd:1 devcontainer feature when
    the image does not include one.

That makes gh a practical first implementation dependency even if direct REST
is used for some control-plane calls.

Recommended implementation strategy

Use a hybrid gh plus REST design, with all subprocess calls routed through
Crabbox Runtime.Exec and all HTTP calls routed through Runtime.HTTP.

The strongest Phase 1 path:

  1. Require gh on PATH, unless explicit REST-only mode is later designed.
  2. Use gh auth status or a lightweight authenticated gh api call in
    doctor to prove the user has GitHub API access without printing tokens.
  3. Resolve the target repository from githubCodespaces.repo, --repo, or the
    current git remote using Crabbox's existing GitHub repo parsing helpers.
  4. Before creation, call repository defaults and permissions-check endpoints
    where possible so missing Codespaces entitlement, missing repo access,
    unaccepted devcontainer permissions, or unavailable machine types fail before
    Crabbox creates a lease claim.
  5. Create the codespace with POST /repos/{owner}/{repo}/codespaces or gh codespace create, passing ref, machine, devcontainer path, working directory,
    idle timeout, retention, and display name.
  6. Poll gh codespace view --json ... or GET /user/codespaces/{name} until
    the state is usable.
  7. Generate an OpenSSH config for that codespace with gh codespace ssh --config -c <name>.
  8. Store the generated config in a private per-lease routing file, mode 0600,
    similar to providers that need provider-specific SSH/proxy state.
  9. Return an SSHTarget that uses OpenSSH with that config. The exact mechanics
    should follow existing proxy-based providers such as Tenki, KubeVirt,
    Sprites, or External rather than hardcoding a public host assumption.
  10. Set the remote work root to the repository's codespace workspace path by
    default, for example /workspaces/<repo-name>/crabbox, unless the user
    configured githubCodespaces.workRoot.
  11. Let core Crabbox perform sync and command execution over SSH.
  12. On release, choose stop or delete based on config:
    • default: delete a Crabbox-created, non-kept codespace;
    • optional: stop kept codespaces so state can be reused;
    • never delete a codespace that Crabbox did not create or cannot identify as
      owned by the local claim.

Do not make the first implementation depend on an undocumented internal VS Code
or Codespaces protocol. If gh codespace ssh --config cannot provide a stable
OpenSSH target for Crabbox, downgrade the implementation plan to a delegated-run
provider that shells through gh codespace ssh -c <name> -- <command> and
documents the reduced sync/artifact surface.

Configuration

Suggested config:

provider: github-codespaces
target: linux
class: standard
githubCodespaces:
  repo: ""
  ref: ""
  machine: ""
  devcontainerPath: ""
  workingDirectory: ""
  geo: ""
  idleTimeout: 30m
  retentionPeriod: 1h
  deleteOnRelease: true
  ghPath: gh
  workRoot: ""

Suggested flags:

--github-codespaces-repo
--github-codespaces-ref
--github-codespaces-machine
--github-codespaces-devcontainer-path
--github-codespaces-working-directory
--github-codespaces-geo
--github-codespaces-idle-timeout
--github-codespaces-retention-period
--github-codespaces-delete-on-release
--github-codespaces-gh
--github-codespaces-work-root

Suggested environment overrides:

GH_TOKEN / GITHUB_TOKEN                         GitHub API token used by gh/api
CRABBOX_GITHUB_CODESPACES_REPO                  owner/repo override
CRABBOX_GITHUB_CODESPACES_REF                   branch or ref override
CRABBOX_GITHUB_CODESPACES_MACHINE               machine type, e.g. standardLinux32gb
CRABBOX_GITHUB_CODESPACES_DEVCONTAINER_PATH     devcontainer path override
CRABBOX_GITHUB_CODESPACES_WORKING_DIRECTORY     codespace working directory
CRABBOX_GITHUB_CODESPACES_GEO                   requested geo
CRABBOX_GITHUB_CODESPACES_IDLE_TIMEOUT          idle timeout as Go duration
CRABBOX_GITHUB_CODESPACES_RETENTION_PERIOD      retention as Go duration
CRABBOX_GITHUB_CODESPACES_DELETE_ON_RELEASE     true/false
CRABBOX_GITHUB_CODESPACES_GH                    gh executable path
CRABBOX_GITHUB_CODESPACES_WORK_ROOT             Crabbox sync work root

Do not accept GitHub tokens as command-line arguments. Keep tokens in gh auth,
environment variables, or the user's credential store.

--class can map to a small set of GitHub machine types only after the provider
can query available machine types for the selected repo. Until then, explicit
githubCodespaces.machine / --github-codespaces-machine is safer than guessing
global names. If --type is already the generic exact machine-type flag in
Crabbox, map it to Codespaces machine.

Lifecycle

Phase 1 lifecycle:

  1. Resolve GitHub repo and ref.
  2. Validate target=linux; Codespaces is a Linux devcontainer surface for this
    provider.
  3. Validate gh availability and authenticated access.
  4. Check repository Codespaces defaults and devcontainer permission acceptance
    when the endpoints are available.
  5. Resolve or validate machine type from repository machine types.
  6. Allocate a Crabbox lease id and slug.
  7. Create a codespace with a display name that embeds the Crabbox slug/lease in
    a human-readable way.
  8. Record a local claim containing:
    • provider = github-codespaces
    • lease id
    • slug
    • repo owner/name
    • ref
    • codespace name
    • environment id
    • machine
    • devcontainer path
    • working directory
    • authenticated GitHub login when available
    • delete-on-release policy
  9. Poll until the codespace is available.
  10. Generate and store per-lease OpenSSH config through gh codespace ssh --config -c <codespace>.
  11. Return an SSH target using that config and a readiness check that proves
    git, rsync, tar, and the configured work root are usable. Do not
    assume python3, Node.js, or npm are present in a minimal Codespaces base
    image; install or validate them only when Crabbox core or a requested
    workflow actually needs them.
  12. Let core Crabbox run sync/command/ssh flows.
  13. Touch/status should refresh state from GitHub and update local labels only;
    there is no provider-side Crabbox tag equivalent.
  14. Stop should delete or stop the codespace according to ownership and
    deleteOnRelease.
  15. Cleanup should only act on codespaces with complete local Crabbox claim
    state and matching GitHub identity/repo. Without local claim proof, it may
    report candidate names but should not delete them.

Ownership and cleanup safety

Codespaces does not expose cloud-style arbitrary resource tags equivalent to
DigitalOcean, Linode, or Hetzner. Use local claims as the primary ownership
source, plus display-name naming as a human hint only.

Suggested display name:

crabbox <slug> <short-lease-id>

Suggested local claim identity fields:

provider=github-codespaces
lease=<cbx_...>
slug=<slug>
repo=<owner>/<repo>
ref=<ref>
codespace=<codespace_name>
environment_id=<environment_id>
github_login=<login>
target=linux
delete_on_release=<true|false>
expires_at=<unix-seconds>

Stop/delete should refuse when:

  • the local claim is absent and --reclaim was not supplied;
  • the claim provider is not github-codespaces;
  • the claim's repo or GitHub login does not match the live codespace;
  • the live codespace name/environment id differs from the claim;
  • the codespace has unsaved changes and the requested operation would require a
    forced delete, unless the user explicitly passes a force flag that Crabbox
    wires through intentionally.

Cleanup should be conservative. Because Codespaces are personal development
environments, accidental deletion is more damaging than leaving a stale stopped
codespace. The first PR should prefer cleanup --dry-run and claim-backed
delete only.

Devcontainer and SSH-server contract

Crabbox should document this provider's strongest prerequisite plainly:

  • A Codespaces devcontainer image must expose SSH for gh codespace ssh.
  • If the image does not include SSH, users can add the devcontainer SSHD feature:
{
  "features": {
    "ghcr.io/devcontainers/features/sshd:1": {
      "version": "latest"
    }
  }
}

The provider should detect SSH config/readiness failures and return a clear
error that tells the user to add SSHD to the devcontainer rather than presenting
it as a generic Crabbox sync failure.

Implementation outline

Likely files to add or modify:

File Change
internal/providers/githubcodespaces/provider.go Register provider name/aliases, spec, flags, Configure, ConfigureDoctor, and server-type mapping.
internal/providers/githubcodespaces/backend.go Implement acquire, resolve, list, release, touch, cleanup, and doctor.
internal/providers/githubcodespaces/client.go Wrap gh api or direct REST calls for create/list/view/start/stop/delete/machines/defaults/permissions.
internal/providers/githubcodespaces/gh.go Wrap gh codespace subprocess calls through Runtime.Exec, including ssh --config.
internal/providers/githubcodespaces/ssh_config.go Parse/store generated OpenSSH config and construct the Crabbox SSHTarget.
internal/providers/githubcodespaces/provider_test.go Provider spec, aliases, target/features, flag behavior.
internal/providers/githubcodespaces/client_test.go Fake HTTP/API fixtures, status parsing, redaction, retry/error handling.
internal/providers/githubcodespaces/gh_test.go Recording command runner tests for every gh invocation and argv redaction.
internal/providers/githubcodespaces/backend_test.go Fake lifecycle tests for acquire/resolve/list/release/cleanup and SSH target construction.
internal/providers/all/all.go Blank-import the provider package.
internal/providers/all/all_test.go Add registration/discovery coverage if the test enumerates built-ins.
internal/cli/config.go Add typed GitHubCodespacesConfig, file config, defaults, env overrides, and config show support.
internal/cli/config_test.go Config file/env/default/redaction coverage.
docs/providers/github-codespaces.md Provider runbook.
docs/providers/provider-metadata.json Add generated matrix metadata.
docs/providers/README.md Regenerate with node scripts/generate-provider-matrix.mjs.
docs/features/providers.md Add direct-provider note if needed.
docs/source-map.md Add the new provider package and docs paths.
scripts/live-github-codespaces-smoke.sh Optional guarded live smoke.
scripts/live-github-codespaces-smoke.test.js Test live-smoke classification and redaction without live GitHub calls.

Do not touch run.go, repo.go, coordinator.go, or shared provider
interfaces unless implementation proves a provider-neutral extension is required.
The provider authoring guide explicitly treats such changes as a checkpoint.

Tests and docs

Implementation should include:

  • Provider registration tests so github-codespaces, codespaces, and
    gh-codespaces resolve as expected.
  • Provider spec tests proving Linux-only, direct-only, SSH/sync/cleanup
    behavior.
  • Config tests for YAML, environment overrides, defaults, and redaction.
  • Command-runner tests proving:
    • gh is invoked through Runtime.Exec;
    • no token appears in argv;
    • repo/ref/machine/devcontainer/timeout/retention flags are passed correctly;
    • gh codespace ssh --config -c <name> is called for SSH target generation;
    • delete/stop commands include noninteractive force only where explicitly
      intended.
  • API/client tests proving:
    • create request includes repo/ref/machine/devcontainer/working directory,
      idle timeout, retention, and display name;
    • list/view/start/stop/delete states are parsed;
    • 401/403/404/409/422/503 errors produce actionable, secret-safe diagnostics;
    • Retry-After is honored for rate/temporary failures where exposed;
    • pending-operation states do not pretend SSH is ready.
  • Backend tests for:
    • acquire happy path;
    • resolve by lease id, slug, and codespace name;
    • release delete-on-release and stop-on-release modes;
    • cleanup dry-run and claim-backed delete;
    • missing SSH server failure message;
    • identity mismatch refusal;
    • no local claim means no destructive cleanup by default.
  • Docs:
    • docs/providers/github-codespaces.md;
    • generated provider matrix update;
    • docs/source-map.md;
    • explicit devcontainer SSHD prerequisite;
    • token/auth guidance and no-token-on-argv warning;
    • limitations around no desktop/browser/code/coordinator in Phase 1.

Suggested opt-in live smoke:

CRABBOX_LIVE=1 \
CRABBOX_LIVE_PROVIDERS=github-codespaces \
CRABBOX_GITHUB_CODESPACES_REPO=example-org/example-repo \
scripts/live-github-codespaces-smoke.sh

The smoke should:

  1. Build bin/crabbox.
  2. Verify gh auth status.
  3. Require a repo configured for Codespaces and an SSH-capable devcontainer.
  4. Create a small codespace with a short idle timeout and retention period.
  5. Run bin/crabbox status --provider github-codespaces --id <lease> --wait.
  6. Run bin/crabbox run --provider github-codespaces --id <lease> --no-sync -- echo crabbox-codespaces-ok.
  7. Run a tiny sync-backed command if the fixture repo is safe for rsync.
  8. Stop/delete the codespace.
  9. Verify no Crabbox-owned claim-backed Codespaces remain.

Final classifications should include:

classification=live_github_codespaces_smoke_passed
classification=environment_blocked
classification=auth_blocked
classification=quota_or_billing_blocked
classification=repo_policy_blocked
classification=ssh_server_missing
classification=validation_failed

Acceptance criteria

  • crabbox providers lists github-codespaces as a Linux SSH-lease provider.
  • Aliases codespaces and gh-codespaces resolve if maintainers accept the
    alias surface.
  • crabbox doctor --provider github-codespaces performs only non-mutating
    checks: gh availability, GitHub auth, repo access, Codespaces availability,
    machine/default discovery, and claim-backed inventory.
  • crabbox warmup --provider github-codespaces --github-codespaces-repo owner/repo
    creates or starts a codespace and returns a Crabbox lease id and slug.
  • crabbox run --provider github-codespaces -- echo ok can execute over the
    generated OpenSSH target when the devcontainer includes SSHD.
  • crabbox ssh --provider github-codespaces --id <lease-or-slug> connects
    through the same provider-specific SSH route.
  • crabbox list/status --provider github-codespaces --json show normalized
    lease state without leaking tokens or generated SSH config secrets.
  • crabbox stop --provider github-codespaces <lease-or-slug> stops or deletes
    only the claim-backed codespace according to config.
  • crabbox cleanup --provider github-codespaces --dry-run reports only
    claim-backed Crabbox codespaces and does not mutate anything.
  • Destructive cleanup refuses foreign, mismatched, or claimless codespaces.
  • Errors do not print GH_TOKEN, GITHUB_TOKEN, authorization headers,
    generated SSH private key material, or full OpenSSH config contents.
  • Docs explain auth, repo/ref/devcontainer/machine settings, the SSHD
    prerequisite, lifecycle, cleanup safety, and Phase 1 limitations.
  • Unit tests use fake HTTP/command runners and do not require live GitHub
    credentials.
  • Optional live smoke either passes or exits with one of the explicit
    classifications above.

Verification commands for the implementation PR

go test ./internal/providers/githubcodespaces ./internal/providers/all ./internal/cli
go test -race ./internal/providers/githubcodespaces ./internal/providers/all ./internal/cli
go vet ./...
npm test --prefix worker
node scripts/generate-provider-matrix.mjs
scripts/check-docs.sh

Optional live validation:

CRABBOX_LIVE=1 \
CRABBOX_LIVE_PROVIDERS=github-codespaces \
CRABBOX_GITHUB_CODESPACES_REPO=example-org/example-repo \
scripts/live-github-codespaces-smoke.sh

Research notes

Local GitHub docs inspected:

  • docs/content/rest/codespaces/codespaces.md
  • docs/content/rest/codespaces/machines.md
  • docs/src/rest/data/fpt-2022-11-28/codespaces.json
  • docs/src/rest/data/ghec-2026-03-10/codespaces.json
  • docs/content/codespaces/developing-in-a-codespace/using-github-codespaces-with-github-cli.md
  • docs/content/codespaces/reference/security-in-github-codespaces.md
  • docs/content/codespaces/setting-up-your-project-for-codespaces/adding-a-dev-container-configuration/introduction-to-dev-containers.md

Crabbox docs and source inspected:

  • docs/features/provider-authoring.md
  • docs/provider-backends.md
  • docs/providers/README.md
  • docs/providers/digitalocean.md
  • docs/providers/daytona.md
  • docs/providers/semaphore.md
  • docs/providers/tenki.md
  • docs/source-map.md
  • internal/cli/provider_backend.go
  • internal/cli/config.go
  • internal/providers/all/all.go
  • internal/providers/digitalocean
  • internal/providers/daytona
  • internal/providers/semaphore
  • internal/providers/tenki
  • internal/providers/sprites

Official current references checked:

Live verification notes

Verified live against the coygeek GitHub account on 2026-06-13 with a
short-lived GitHub token. Do not copy tokens into issues, PRs, logs, commits, or
command-line arguments.

Disposable fixture:

  • Fixture repo created: coygeek/crabbox-codespaces-smoke-june13.
  • Default branch: main.
  • Fixture files added:
    • README.md
    • .devcontainer/devcontainer.json
  • The devcontainer uses mcr.microsoft.com/devcontainers/base:ubuntu and the
    ghcr.io/devcontainers/features/sshd:1 feature.
  • The fixture repo was intentionally retained so the next developer can rerun
    the smoke without recreating the repo. The live codespace created during this
    verification was deleted.

Token/API behavior proved:

  • GH_TOKEN=<redacted> authenticated as coygeek.
  • GET /user/codespaces?per_page=1 returned HTTP 200 with
    X-Accepted-GitHub-Permissions: codespaces=read.
  • gh codespace list --json ... worked and initially returned an empty list.
  • GET /repos/coygeek/crabbox-codespaces-smoke-june13/codespaces/new worked
    and returned billable_owner=coygeek; most defaults were null before an
    explicit create request.
  • GET /repos/coygeek/crabbox-codespaces-smoke-june13/codespaces/machines
    returned four Linux machines:
    • basicLinux32gb - 2 cores, 8 GB RAM, 32 GB storage
    • standardLinux32gb - 4 cores, 16 GB RAM, 32 GB storage
    • premiumLinux - 8 cores, 32 GB RAM, 64 GB storage
    • largePremiumLinux - 16 cores, 64 GB RAM, 128 GB storage
  • GET /repos/coygeek/crabbox-codespaces-smoke-june13/codespaces/permissions_check?ref=main&devcontainer_path=.devcontainer/devcontainer.json
    returned { "accepted": true }.
  • DELETE /user/codespaces/{name} returned HTTP 202 with
    X-Accepted-GitHub-Permissions: codespaces=write.

Codespace lifecycle proved:

  • Create endpoint used:
    POST /repos/coygeek/crabbox-codespaces-smoke-june13/codespaces.
  • Create parameters used:
    • ref=main
    • machine=basicLinux32gb
    • devcontainer_path=.devcontainer/devcontainer.json
    • idle_timeout_minutes=10
    • retention_period_minutes=60
    • display_name="crabbox smoke june13"
  • Created codespace name followed GitHub's generated name format, e.g.
    crabbox-smoke-june13-<suffix>.
  • Observed create state transition:
    Provisioning -> Available.
  • gh codespace view --json ... returned:
    • repository as the string coygeek/crabbox-codespaces-smoke-june13, not
      an object. Provider code should not assume repository.nameWithOwner for
      gh JSON output.
    • devcontainerPath=.devcontainer/devcontainer.json
    • machineName=basicLinux32gb
    • idleTimeoutMinutes=10
    • retentionPeriodDays=0 for a 60-minute retention request.
  • Stop/start endpoints worked:
    • POST /user/codespaces/{name}/stop
    • POST /user/codespaces/{name}/start
  • Observed stop/start state transitions:
    ShuttingDown -> Shutdown -> Starting -> Available.
  • After delete, gh codespace list -R coygeek/crabbox-codespaces-smoke-june13
    returned an empty list.

SSH and sync behavior proved:

  • gh codespace ssh --config -c <name> generated a 0600 OpenSSH config with:
    • host alias format cs.<codespace-name>.<branch>
    • User vscode
    • a ProxyCommand that calls GitHub CLI's Codespaces SSH stdio path
    • IdentityFile ~/.ssh/codespaces.auto
  • Plain OpenSSH with the generated config worked:
    ssh -F /tmp/crabbox-codespaces-smoke-ssh-config <generated-host-alias> 'echo openssh-ok'.
  • Remote command execution over plain OpenSSH worked.
  • rsync -e "ssh -F /tmp/crabbox-codespaces-smoke-ssh-config" to /tmp worked
    and the transferred proof file was readable remotely.
  • The same generated config still worked after stop/start.
  • Direct gh codespace ssh -c <name> -- <command> failed in this environment
    with:
    vscode@localhost: Permission denied (publickey,password).
    shell closed: exit status 255
  • Provider implementation should therefore prefer the generated config plus
    plain ssh -F <config> / rsync -e "ssh -F <config>" path for command and
    sync execution. Do not assume direct gh codespace ssh -- <command> is
    equivalent.

Remote environment observed:

  • Remote user: vscode.
  • Default remote working directory for SSH: /home/vscode.
  • Repository workspace exists at:
    /workspaces/crabbox-codespaces-smoke-june13.
  • Passwordless sudo works: sudo -n true.
  • Present by default in the minimal fixture:
    • git=/usr/local/bin/git
    • rsync=/usr/bin/rsync
    • tar=/usr/bin/tar
    • sudo=/usr/bin/sudo
    • apt-get=/usr/bin/apt-get
  • Missing by default in the minimal fixture:
    • python3
    • node
    • npm
  • Installing Python proved possible:
    sudo apt-get update -qq && sudo apt-get install -y -qq python3, after which
    python3 --version reported Python 3.12.3.

Open questions

  • Should the canonical provider name be github-codespaces or simply
    codespaces? Recommendation: github-codespaces canonical, codespaces and
    gh-codespaces aliases, because the provider is GitHub-specific and
    codespaces alone is generic.
  • Should Phase 1 create through direct REST or through gh codespace create?
    Recommendation: implement both behind one client if cheap, but use gh first
    for parity with local auth and SSH behavior.
  • Should release default to delete or stop? Recommendation: delete non-kept
    Crabbox-created leases by default to avoid cost/retention surprises, but stop
    kept leases.
  • Can Crabbox safely parse and use generated gh codespace ssh --config
    without modifying the user's global ~/.ssh/config? Recommendation: store a
    per-lease private config file and pass it explicitly to OpenSSH.
  • Should the provider support --fresh-pr by creating a codespace from a pull
    request endpoint? Recommendation: defer until the base repo/ref flow is stable.
  • Which exact GitHub machine type should map to Crabbox standard? Recommendation:
    do not hardcode global mapping until machine discovery is implemented against
    the selected repository.

Implementation PR

Implemented by #347.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal priority bug or improvement with limited blast radius.clawsweeper:linked-pr-openClawSweeper found an open linked pull request for this issue.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.issue-rating: 🌊 off-meta tidepoolIssue quality rating does not apply to this item.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions