Skip to content

Testing guide + coverage matrix: exercise every connector lifecycle, with a two-tier CI gate before main #944

Description

@zozo123

Summary

Crabbox has 71 registered providers but no single place that says how to test a connector's full lifecycle, no complete picture of which providers are covered, and no CI gate that exercises any lifecycle before code lands on main. This issue documents the testing method, publishes a verified coverage matrix, and proposes a two-tier CI design that stays inside the constraints from the closing guidance on #176 and #175.

Verified against current main:

  • 71 providers registered in internal/providers/all/all.go, matching docs/providers/provider-metadata.json and the 71 pages under docs/providers/.
  • 30 providers have a dedicated smoke runner in scripts/ (29 live-*-smoke.sh shell scripts; codesandbox uses Node runners scripts/live-codesandbox-smoke.test.js + live-codesandbox-smoke-classify.test.js).
  • 43 providers are drivable through the scripts/live-smoke.sh matrix (CRABBOX_LIVE_PROVIDERS), via its generic provider_smoke() path or an inline custom function.
  • Only 4 providers have hermetic lifecycle unit tests that run in go test -race ./... today: scaleway (internal/providers/scaleway/backend_lifecycle_test.go), nebius, nomad, firecracker.
  • .github/workflows/ contains zero smoke or lifecycle invocations — no workflow references CRABBOX_LIVE or any live-*-smoke.sh.
  • 20 providers have no lifecycle coverage of any kind (list below).

The lifecycle a connector test must exercise

From the backend contract in internal/cli/provider_backend.go:

Stage Contract CLI stage used by smoke scripts
Acquire / Warmup SSHLeaseBackend.Acquire, DelegatedRunBackend.Warmup crabbox warmup
Resolve / readiness SSHLoginBackend.Resolve, delegated Status crabbox status --wait
Exec + sync DelegatedRunBackend.Run (RunRequest incl. downloads/artifact globs), SSH exec crabbox run --shell, crabbox ssh
Touch (keepalive) LeaseTouchBackend.Touch exercised by status --wait
List / inventory SSHLeaseBackend.List, JSONListBackend.ListJSON crabbox list --json, crabbox inspect --json
Copy / ports CopyBackend.Copy, PortsBackend.Ports crabbox cp, crabbox ports
Snapshot / checkpoint (optional) NativeCheckpointLifecycleProvider.* provider-specific
Pause / Resume (optional) PausableBackend.Pause/Resume live-exercised only for tenki and codesandbox today
Release / Stop SSHLeaseBackend.ReleaseLease (with ProviderIdentityExpectation validation), delegated Stop crabbox stop
Orphan cleanup CleanupBackend.Cleanup (DryRun supported) crabbox cleanup --dry-run, scripts/aws-crabbox-orphan-audit.sh

How to test a connector today (the recipe this issue wants documented in docs/)

  1. Hermetic lifecycle unit test — a table-driven backend_lifecycle_test.go against a fake API (pattern: internal/providers/scaleway/backend_lifecycle_test.go, e.g. TestScalewayAcquireListResolveTouchReleaseLifecycle). Runs in CI via go test -race ./.... This is the only tier that can gate merges for every provider.
  2. Guarded live smokeCRABBOX_LIVE=1 CRABBOX_LIVE_PROVIDERS=<p> CRABBOX_BIN=bin/crabbox scripts/live-smoke.sh, or the provider's dedicated scripts/live-<p>-smoke.sh. All scripts arm EXIT/RETURN traps that crabbox stop their leases, and several classify provider-capacity failures (quota_blocked / environment_blocked) separately from regressions.
  3. Opt-in Go live smokes//go:build smoke tests (islo, morph, wandb) run only with the smoke tag plus provider env gates (e.g. ISLO_API_KEY + CRABBOX_LIVE_ISLO_PAUSE_RESUME=1). These are excluded from CI by build tag and undocumented in docs/features/provider-live-smoke.md.

Coverage matrix — the gaps

20 providers with zero lifecycle coverage (no dedicated smoke runner, not in the live-smoke.sh matrix, no lifecycle unit test):

apple-machine, ascii-box, azure, azure-dynamic-sessions, cloudflare-sandbox, exe-dev, fastapi-cloud, freestyle, gcp, hostinger, hyperv, islo, mxc, opencomputer, parallels, railway, ssh, tensorlake, upstash-box, windows-sandbox

Notable: azure and gcp are majors with open cleanup-safety issues (#930, #931) yet no lifecycle test exercises their release path. ssh should be testable hermetically against 127.0.0.1 on any runner. islo has live Go tests but no shell smoke and is absent from live-smoke.sh (it needs a custom function like e2b_smoke because generic crabbox ssh requires the external islo CLI).

Only 4/71 providers have hermetic lifecycle unit tests. That is the cheapest, highest-leverage gap: those tests need no secrets and gate every PR.

Proposal: .github/workflows/connector-lifecycles.yml, two tiers

Designed to address the reasons #175 was closed (secret-bearing runners, automation risk, provider-list drift):

Tier 1 — hermetic, required check on every PR / push to main. No secrets at all.

  • docker-sandbox full lifecycle (scripts/live-docker-sandbox-smoke.sh — needs no env), docker-sandbox trust boundary, local-container via live-smoke.sh, firecracker readiness (read-only doctor contract), ssh-to-localhost lifecycle (new small script), apple-vm on macos-15.
  • Lives as a matrix job; can sit inside ci.yml so dependabot-auto-merge.yml (which keys off the CI workflow conclusion) inherits it without changes.

Tier 2 — live cloud matrix: schedule (nightly) + workflow_dispatch only. Never runs on pull_request, so fork PRs can never reach secrets.

  • Secrets scoped to a dedicated live-smoke GitHub environment (required-reviewer gating for dispatches comes free — same pattern coordinator-deploy.yml uses for coordinator).
  • Green-skip rows whose secret is unset (the coordinator-deploy.yml probe pattern), so partially provisioned secrets never red-X the nightly.
  • fail-fast: false, max-parallel: 4 (spend/rate cap), timeout-minutes: 30, per-provider concurrency group with cancel-in-progress: false — cancelling mid-provision is how orphans happen.
  • Treat quota_blocked / environment_blocked classifications as warnings, not failures.
  • Trailing orphan-audit job (if: always()) running scripts/aws-crabbox-orphan-audit.sh read-only (its --terminate fails closed by design) that fails when crabbox-tagged instances outlive their leases.
  • No second provider list: generate the live matrix from docs/providers/provider-metadata.json (extend scripts/generate-provider-matrix.mjs) or reuse CRABBOX_LIVE_PROVIDERS defaults, so the workflow cannot drift from the registry — this was an explicit concern on Proposal: add live provider E2E GitHub Actions matrix #176.
  • All uses: SHA-pinned (enforced by scripts/workflow_action_pins.go via the CI Scripts job) and a scripts/connector-lifecycles-workflow.test.js shape test asserting: no secrets in tier 1, no pull_request trigger on tier 2, continue-on-error on live rows.

Secret names match what the scripts already read from env: AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY, HCLOUD_TOKEN, DIGITALOCEAN_TOKEN, LINODE_TOKEN, VULTR_API_KEY, SCW_*, TENCENTCLOUD_*, LAMBDA_API_KEY, RUNPOD_API_KEY, VAST_API_KEY (+ CRABBOX_LIVE_VAST_MAX_DPH_TOTAL price cap), BL_API_KEY/BL_WORKSPACE, VERCEL_TOKEN, SMOLMACHINES_API_KEY, SUPERSERVE_API_KEY, OPEN_SANDBOX_API_KEY, CROWNEST_API_KEY, WANDB_API_KEY/WANDB_ENTITY_NAME. Self-hosted-infra providers (nomad, proxmox, xcp-ng, kubevirt, agent-sandbox, phala) stay out of hosted runners; the hydrate.yml self-hosted-label pattern covers them later.

Task checklist

  • Add a docs/ testing guide capturing the lifecycle table and the three-tier recipe above (candidate: extend docs/features/provider-live-smoke.md).
  • Document the //go:build smoke live-test env vars (ISLO_API_KEY, CRABBOX_LIVE_ISLO_PAUSE_RESUME, CRABBOX_LIVE_ISLO_IMAGE, morph/wandb equivalents) in that guide.
  • Tier 1 workflow (hermetic matrix) + workflow shape test; wire as required check.
  • scripts/live-ssh-localhost-smoke.sh (hermetic, mirrors live-docker-sandbox-smoke.sh).
  • Hermetic backend_lifecycle_test.go for high-traffic providers missing one (start: aws, azure, gcp, e2b, daytona, islo, railway) — pattern from internal/providers/scaleway/backend_lifecycle_test.go; long-term goal: all 71.
  • islo smoke coverage: islo_smoke() function in scripts/live-smoke.sh (warmup → status --wait → run → pause → resume → stop; skip generic crabbox ssh).
  • Dedicated or matrix smoke coverage for the remaining zero-coverage providers listed above.
  • Tier 2 live workflow behind the live-smoke environment — only after maintainers decide the repository secret/provider policy, per the closing guidance on Proposal: add live provider E2E GitHub Actions matrix #176; dispatch it once and attach the run link as live proof.

I can send tier 1 (hermetic gate + docs guide + shape test) as a PR first since it needs no secret policy decision, and hold tier 2 until the policy call is made.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Low-risk cleanup, docs, polish, ergonomics, or speculative feature.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.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.impact:otherThis issue has meaningful maintainer-visible impact outside the owned taxonomy.issue-rating: 🌊 off-meta tidepoolIssue quality rating does not apply to this item.

    Type

    No type

    Fields

    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