v0.1.0-rc3 — Sprint 21 cPanel adapter foundation + public launch prep
Pre-releaseWebox v0.1.0-rc3 — Release notes
Tag: v0.1.0-rc3 · published 2026-05-25 as a GitHub pre-release.
Type: Release candidate refresh — Sprint 21 (cPanel adapter foundation + public launch prep) layered onto the rc2 baseline.
RC3 is scope-additive over rc2. The MVP product surface is unchanged for
smallhost-deviloperators; this RC ships read-only diagnostic and infrastructure for cPanel. Promote tov0.1.0GA by re-tagging the same SHA after.cursor/skills/release-check/SKILL.mdis fully ticked. The next code-affecting work is the mutating cPanel adapter (Sprint 22 →v0.2.0-rc1).
What changed since v0.1.0-rc2
Sprint 21 (TASK-21.1 .. 21.6 + 21.8) lands in a single autonomous session: a full read-only cPanel client (HTTPS + SSH), a diagnostic CLI, live SSH probing for the preset registry, and the operator-facing artefacts the public launch needs (README EN, asciinema cast).
New transport layer — providers/cpanel/uapi/
A standalone, importable package the future providers/cpanel adapter will compose. No mutating endpoints are reachable from this client today — the MutatingClient interface returns ErrSprintScopeNotMutable so the type system enforces the "no destructive ops in v0.2-rc" guardrail.
- HTTPS path (
Clientinclient.go+transport.go):- Typed
ListDomains / ListPassengerApps / ListMysqlDatabases / ListSSLKeysoverhttps://host:2083/execute/<Module>/<Function>. - HTTPS-only (constructor refuses
http://),Authorization: cpanel <user>:<token>, 4 MiB body cap, configurable*http.Client. - Exponential backoff on 429 / 5xx (500 ms × 2ⁿ, capped at 3 retries + injectable for fast tests).
- 10 typed sentinels (
ErrAuthenticationFailed,ErrRateLimited,ErrMalformedResponse,ErrModuleFunctionDenied,ErrTransportUnavailable, …) — operators canerrors.Iswithout string-matching.
- Typed
- SSH fallback (
SSHFallbackinssh.go+sshpool.go):- Shells out to
uapi --user=<user> --output=jsonpretty <Module> <function>over the project's SSH pool. - Every shell argument routed through
'\''-escapingshellQuote(defence in depth — the threat model is documented in the 10-case test table including$(rm -rf /)/`whoami`/O'Brien/; ls; #injection attempts). - The
SSHRunnerseam keeps unit tests dependency-free; productionSSHPoolRunnerdistinguishes non-zero exit (returned via exitCode) from transport failure (wrapped inErrTransportUnavailable).
- Shells out to
- Composite layer (
Compositeincomposite.go):- Closed
Readerinterface plus generics-driven dispatcher prefers HTTPS, fails over to SSH onerrors.Is(err, ErrTransportUnavailable), surfaces auth / rate-limit / malformed / module-denied verbatim. - Generic
tryComposite[T any]removes runtime type assertions — eachList*method is a one-line forward.
- Closed
- Decoders (
decoders.go):- Shape-tolerant
decodeListResponse[T]accepts modern object-wrapper + top-level array + legacy map-keyed shapes (cPanel < 88 still in the wild). - Stable id-sort keeps test fixtures and TUI rows identical across cPanel versions.
- Shape-tolerant
Coverage: 77.9 % across 24 unit tests. 7 golden fixtures cover happy + edge paths; research-derived from public api.docs.cpanel.net until the live test account onboarding (Sprint 22 TASK-22.0) backfills them.
New CLI — webox doctor cpanel
webox doctor cpanel \
--host=panel.example.com --user=operator \
[--token=...] [--api-port=2083] [--ssh-port=22] \
[--timeout=30s] [--no-ssh] [--no-uapi] [--json]
Exercises all four read-only modules in a single call. Routes through HTTPS when --token is supplied, falls over to SSH on transport failure. Section status taxonomy: OK / DISABLED (ErrModuleFunctionDenied — not a Webox failure, counts as OK in the rollup) / AUTH_FAILED / UNREACHABLE / FAILED. Rollup verdict: OK (all OK / DISABLED, exit 0), DEGRADED (mixed, exit 0), BLOCKED (everything failed, exit 1).
23 unit tests cover validation, rollup 7-case table, builder wiring (HTTPS-only / SSH-only / composite), happy / DEGRADED / BLOCKED outcomes, text + JSON output stability, and CLI flag parsing including the provider new cpanel <X> vs doctor cpanel ambiguity resolution.
Bug discovered + fixed in flight: transport.sleepWithCtx previously returned ctx.Err() unwrapped, so context-cancelled retries surfaced as FAILED instead of UNREACHABLE. The fix wraps ctx.Err() with ErrTransportUnavailable; smoke test against RFC 5737 unreachable IP (192.0.2.1) now correctly returns 4× UNREACHABLE + BLOCKED verdict.
webox doctor preset --probe over real SSH
The Sprint-19 stub became a live execution path. New invocation:
webox doctor preset --id=<preset> --probe \
--host=<host> --user=<user> [--port=N] [--timeout=30s] [--json]
Pure summarization logic (11 unit tests across summarizeProbe / formatProbeText / formatProbeJSON) lives in cmd/webox/probe.go. Production runner shells out to the operator's native ssh binary with BatchMode=yes -o StrictHostKeyChecking=accept-new -o ConnectTimeout=10 — Webox owns no new auth surface (delegates to ~/.ssh/config + ssh-agent).
Output: per-probe block + summary line + confidence score (0-100, integer share of OK probes, rounded down so it's never inflated). JSON schema: preset_id, preset_name, host, user, confidence, ok_count, mismatch_count, failed_count, results[]. Exit codes: 0 (all OK), 1 (≥1 FAILED), 2 (≥1 MISMATCH).
Launch artefacts
- README EN final at 58 lines (
README.md) — single H1, value proposition, install snippet, "What works today" (5 bullets with Sprint 20 keybindings), provider-adapter invitation, 4-row roadmap, contributing/security/license. All 13 internal links verified. RC2 badge bumped to RC3 will follow this release. - asciinema 3.x cast + GIF — deterministic 45–60 s tour via
scripts/record-demo.sh, pinned to120×35Bento Ultra framing. Embedded inline in README EN. Artefacts:docs/screenshots/sprint-21/demo.cast+demo.gif.
Documentation
- Sprint 21 plan closed with full Outcome section: path-A selected (full parallel), 6/8 tasks done, TASK-21.7 (cPanel test account) carried over to Sprint 22.
- Sprint 21 retro shipped at
docs/retros/2026-05-25-sprint-21.md— what worked, friction, surprises, changes to apply going forward, open questions. - Sprint 22 plan (
docs/sprints/sprint-22-cpanel-adapter-mutations.md) — mutating UAPI client + fullproviders.HostingProviderimplementation + wizard integration + GHA template + E2E +v0.2.0-rc1tag. - Sprint 23 plan (
docs/sprints/sprint-23-second-provider-or-launch.md) — decision-doc: Path A (DirectAdmin) / Path B (CyberPanel) / Path C (Public Launch redux), matrix to be filled at Sprint 22 retro.
Quality bars met
| Gate | Status | Threshold |
|---|---|---|
Tests passing (make test -race) |
✅ green | All packages |
Coverage (make cover-check) |
✅ ≥ 79 % global; new providers/cpanel/uapi/ at 77.9 % |
≥ 70 % global |
Lint (golangci-lint v2) |
✅ 0 issues | 0 issues |
Vulnerability scan (govulncheck) |
✅ clean | 0 known CVEs |
Bento render perf (make bench-check) |
✅ < 5 ms/op | ≤ 5 000 000 ns/op |
Manual smoke (make smoke-test) |
✅ 5 scenarios × 34 assertions × ~83 s | All scenarios green |
CI bundle (make ci) |
✅ green | Full pipeline |
Known gaps + carry-overs
- TASK-21.7 — Live cPanel test account. Blocked on maintainer-side procurement (vendor purchase + H88 partnership outreach). Until it lands, the 7 fixtures in
providers/cpanel/uapi/testdata/stay research-derived; thecpanel-genericpreset remainsresearch(notverified). Sprint 22 starts with TASK-22.0 = account procurement as a P0 gate. - MVP product surface is unchanged for
smallhost-deviloperators. RC3 does not ship a cPanel provider adapter — theproviders/cpanel/cpanel.goadapter implementingproviders.HostingProvider.CreateProject / RemoveProject / ...lands in Sprint 22. RC3 only ships diagnostic + transport. - Mutating ops gated behind a future env-var. Sprint 22's
MutatingClient.Callwill requireWEBOX_CPANEL_MUTATIONS=1as defence in depth on top of the type-system enforcement — operator must opt in explicitly.
Upgrade path
- From v0.1.0-rc2: drop in
weboxbinary; no config migration needed. New CLI surfaces are additive. - Existing
smallhost-devilusers: nothing to do; no behaviour change. - Operators wanting to evaluate cPanel diagnostic:
webox doctor cpanel --host=panel.example.com --user=operator --token=$TOKENreturns a verdict; mutating ops will arrive in v0.2.0-rc1.
Next milestone
Sprint 22 — cPanel adapter part 2 (mutating ops + adapter + wizard + GHA template + E2E + live-account fixtures) ships as v0.2.0-rc1.