mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-09-11 13:28:57 +00:00
665f1918a7
* feat(cli): headless admin bootstrap via --email/--name/--password (BUG-988) Adds non-interactive flags to `pad auth setup` and `pad init` so agents running inside Claude Code or other non-TTY environments can bootstrap a fresh Pad instance without hitting interactive prompts that block forever. - New flags --email, --name, --password on both commands; all three must be supplied together when any one is present (clear error naming the missing flag otherwise). Checked before the remote-mode guard so the headless path works on any server host — the loopback gate is enforced server-side. - runHeadlessSetup() drives the existing POST /api/v1/auth/bootstrap endpoint directly, saves credentials, and respects --format json (emits a LoginResponse-shaped object with user + token). Already-initialized conflict produces a structured JSON error object under --format json. - `pad init` slots headless bootstrap into the bootstrap step only; the rest of init (config, workspace creation, skill install) continues. - Hardens readPassword() with an early non-TTY guard (generic message). - Hardens promptAndBootstrap() with a bootstrap-specific non-TTY guard (points at --email/--name/--password flags) so --cli-prompt on a pipe exits immediately rather than blocking. - Extends `pad init` non-TTY error message to mention the new flags. - Five new tests in cmd/pad/setup_headless_test.go covering success, missing-flag validation, non-TTY guard, already-initialized conflict, and the full init flow including workspace creation. NOTE: --password is visible in process listings (inherent to flag-based injection). Env-var bootstrap (PAD_ADMIN_*) is the tracked follow-up. Claude-Session: https://claude.ai/code/session_01WK9cUjxniBBAihGD5ygjDr * fix(cli): thread bootstrap token, factor shared core, restore readPassword fallback Round-1 codex findings: 1. Bootstrap token not sent on headless path (BLOCKER) Add BootstrapWithToken(email, name, password, token) to cli.Client that sets X-Bootstrap-Token when token is non-empty. Export ReadBootstrapToken from internal/cli/bootstrap.go (was readBootstrapToken) so cmd/pad can call it. Extract doHeadlessBootstrap(cfg, client, email, name, password) as the shared core for both setupCmd and padInitCmd: reads the on-disk token best-effort (absent → empty → loopback gate still covers that case), calls BootstrapWithToken, saves credentials, sets auth token on client. Both headless paths now go through this single function — no divergence. 2. readPassword bufio fallback removed by accident (REGRESSION) Restore the pre-round-1 bufio fallback in readPassword so piped-password flows (e.g. pad auth login --interactive in CI) keep working. The bootstrap wedge is already prevented by the top-of-promptAndBootstrap TTY guard; the generic readPassword fallback is only reached by non-bootstrap callers. 3. Shared core (CLEANUP) padInitCmd now calls doHeadlessBootstrap instead of duplicating Bootstrap + saveCredentials + SetAuthToken. The --format json asymmetry (init vs setup) is resolved by design: pad init is a multi-step flow; for machine-readable bootstrap output agents should use `pad auth setup --email … --format json`. Documented in the inline comment on the headless branch in padInitCmd. Tests added: TestHeadlessSetupSendsBootstrapToken, TestHeadlessSetupNoTokenFileOK, TestReadPasswordFallback. Update internal/cli/bootstrap_test.go for the rename. Claude-Session: https://claude.ai/code/session_01WK9cUjxniBBAihGD5ygjDr * BUG-988 round-2: surface token-read errors, wrap 403 with hint, rescope readPassword test doHeadlessBootstrap: distinguish os.ErrNotExist (absent token → best-effort empty, proceed without header) from other read errors (permissions, etc. → surface with the file path so operators can diagnose rather than silently hitting a confusing 403). Wrap 403/forbidden from BootstrapWithToken with an actionable multi-bullet hint covering loopback gate, token-file path, and PAD_BYPASS_SETUP_TOKEN. ReadBootstrapToken (internal/cli/bootstrap.go): add %w to the ErrNotExist branch so errors.Is(err, os.ErrNotExist) propagates to callers; existing tests and --cli-prompt hint text preserved. TestReadPasswordFallback → TestReadPasswordBufioFallback: rescoped to assert readPassword isolation only; added comment citing BUG-1886 (pre-existing doInteractiveLogin double-bufio.Reader bug). BUG-1886 filed in docapp.