From 96ee8d73023c3619cf761722f6ddddede12fe783 Mon Sep 17 00:00:00 2001 From: Siddartha Aralakuppe Yogesha Date: Tue, 20 Oct 2026 15:31:50 +0530 Subject: [PATCH 01/14] [failproofai-config-account-login] Log in to FailproofAI Cloud from `failproofai config` The CONNECT step opens with a menu: log in through the browser (default), paste an API key, or use open source. Logging in opens a link (or prints it over SSH / with no display) where a person signs up or in, picks or creates an org and authorizes the machine; the CLI polls with a secret only it holds and shows who approved it, for which org. The key is claimed at APPLY, after the daemon installs, so an abandoned run mints nothing. A connected machine is offered "keep" first, or "log in again" first when its saved key no longer works. - src/hooks/cloud-login.ts: start / poll / claim against /api/auth/cli/*, injectable fetch, no redirects followed, only http(s) links ever handed to the opener; older clouds read as unsupported - tui promptBrowserLogin: link printed above the live region (never cut), esc back, ctrl-c cancel, expiry/deny offer a new link, keeps polling through a dropped connection - configure-wizard: Connect menu, claim at apply, re-login note, sudo re-asked at apply when the cache expired during the login - open-browser: canOpenBrowser (false over SSH / no display), openUrl exported - e2e harness __tests__/e2e/layout/cli-login.sh + pty driver - docs: quickstart and CLI reference lead with the login Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 8 + __tests__/e2e/layout/README.md | 6 + __tests__/e2e/layout/cli-login-driver.py | 102 ++++++ __tests__/e2e/layout/cli-login.sh | 280 +++++++++++++++ __tests__/hooks/browser-login-prompt.test.ts | 180 ++++++++++ __tests__/hooks/cloud-login.test.ts | 176 ++++++++++ __tests__/hooks/configure-wizard.test.ts | 343 +++++++++++++++++-- docs/reference/failproof-cli.mdx | 6 +- docs/start/quickstart.mdx | 29 +- src/audit/open-browser.ts | 20 +- src/hooks/cloud-login.ts | 223 ++++++++++++ src/hooks/configure-wizard.ts | 273 ++++++++++++++- src/hooks/tui.ts | 252 ++++++++++++++ 13 files changed, 1847 insertions(+), 51 deletions(-) create mode 100755 __tests__/e2e/layout/cli-login-driver.py create mode 100755 __tests__/e2e/layout/cli-login.sh create mode 100644 __tests__/hooks/browser-login-prompt.test.ts create mode 100644 __tests__/hooks/cloud-login.test.ts create mode 100644 src/hooks/cloud-login.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index d4f9e68b9..a93bc905b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ ## 1.0.12-beta.0 — 2026-10-22 +### Features + +- **Log in to FailproofAI Cloud from `config`.** The connect step now opens with a menu: log in through the browser (the default), paste an API key, or use open source. Logging in opens a link — or prints it over SSH or with no display, to open on any device — where you sign up or sign in, pick or create an org, and authorize the machine; the terminal notices on its own and shows who approved it and for which org. The machine's key is created only when setup finishes, after the daemon is installed, so a run you abandon leaves no key behind. A machine that is already connected is offered "keep" first, or "log in again" first when its saved key no longer works. Needs a FailproofAI Cloud with browser login; an older one says so and pasting a key still works (#TBD) + +### Fixes + +- `config` asks for your sudo password again before installing the daemon when the one given at the start expired while you were answering (5 minutes on macOS by default), instead of failing after everything else was done (#TBD) + ### Dependencies - Combine the open Dependabot PRs (#921, #922, #923) into one: `certifi` 2026.7.22 → 2026.10.19 (GHSA-6q48-6c7w-9gw2) in `fp-cloud-cli` and the Python SDK's test lockfile, and `vite` 8.3.0 → 8.3.4 in the TypeScript SDK's dev lockfile. The Supply Chain gate scans every lockfile, so none of the three could pass on its own (#926) diff --git a/__tests__/e2e/layout/README.md b/__tests__/e2e/layout/README.md index 8ec809f6b..ddb2c2d01 100644 --- a/__tests__/e2e/layout/README.md +++ b/__tests__/e2e/layout/README.md @@ -9,6 +9,7 @@ not depend on — so they are invoked deliberately. | `layout-reset.sh` | nothing | fresh/stale/future layout detection, reset semantics, OSS silence, hook warn-don't-delete-don't-deny | | `cloud-collector.sh` | an AgentEye stack | real connect against a live server, daemon + collector writing layout-2 paths, decisions reaching ClickHouse, disconnect back to OSS | | `systemd-service.sh` | Docker | REAL `systemctl enable --now` as root in a privileged container: service lifecycle, fail-closed, self-heal, reinstall | +| `cli-login.sh` | an AgentEye stack (dashboard + mailpit + its Postgres), Docker, `bun run build` + the release daemon | `config`'s browser login through a real pty in a systemd container: approve, re-login, deny + retry, abandon after approval (no key minted), esc, expiry, revoked saved key, older server, and the person-side refusals (Origin, form posts, no session, start rate limit) | `systemd-service.sh` exists because the service half cannot be tested on a developer machine without a password prompt, and a container gives real systemd @@ -31,6 +32,11 @@ Two things it caught that a mock could not: bash __tests__/e2e/layout/layout-reset.sh bash __tests__/e2e/layout/systemd-service.sh +# cli-login.sh drives the real wizard against a running AgentEye; point it at +# that stack's dashboard, mailpit API and Postgres container. +DASH=http://localhost:3000 MAILPIT=http://localhost:8026 PG_CONTAINER=agenteye-postgres-1 \ + bash __tests__/e2e/layout/cli-login.sh + # cloud-collector.sh expects the stack on the remapped ports (18080/18123) so it # can run alongside an existing project rather than displacing it: docker compose -p aefpai -f docker-compose.yml -f ports.yml up -d diff --git a/__tests__/e2e/layout/cli-login-driver.py b/__tests__/e2e/layout/cli-login-driver.py new file mode 100755 index 000000000..45a465918 --- /dev/null +++ b/__tests__/e2e/layout/cli-login-driver.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +"""Drive `failproofai config` through a real pseudo-terminal, screen by screen. + +Used by cli-login.sh, inside the systemd container, as the unprivileged user. +The wizard only offers browser login to a real terminal, so a pty is the only +honest way to test it end to end. + +Usage: cli-login-driver.py