From 7b4bcf004b3c61e9973c83f51bcb062b51484b16 Mon Sep 17 00:00:00 2001 From: Siddartha Aralakuppe Yogesha Date: Wed, 4 Nov 2026 20:58:46 +0530 Subject: [PATCH 01/15] [failproofai-feat-failproofai-cloud-login] Sign in to `fp` from a browser On a terminal, `fp login` now asks: browser opens a link (or prints it over SSH or with no display), the person authorizes it, and the terminal finishes on its own; email sends the 6-digit code as before. Either way it ends in the same session, because most of `fp` refuses API keys and it never stores one. `--email`, `--json` and anything without a terminal behave as they always did. A Cloud without browser login falls back to the code by itself, including one that has `failproofai config`'s login but drops `kind` and would end in a machine key: `fp` requires the echo, so nothing is approved and nothing is minted. Adds `__tests__/e2e/layout/fp-login.sh`, and fixes `has`/`hasnt` in `cli-login.sh`, which could report the wrong result on large output under pipefail. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 4 + __tests__/e2e/layout/README.md | 7 + __tests__/e2e/layout/cli-login-driver.py | 24 +- __tests__/e2e/layout/cli-login.sh | 6 +- __tests__/e2e/layout/fp-login.sh | 519 ++++++++++++++++++++++ docs/reference/cloud-cli.mdx | 5 +- fp-cloud-cli/CHANGELOG.md | 7 +- fp-cloud-cli/README.md | 14 +- fp-cloud-cli/fp_cli/app.py | 2 +- fp-cloud-cli/fp_cli/auth.py | 306 ++++++++++++- fp-cloud-cli/fp_cli/commands/auth_cmds.py | 213 +++++++-- fp-cloud-cli/fp_cli/output.py | 39 +- fp-cloud-cli/fp_cli/select.py | 47 +- fp-cloud-cli/skill/SKILL.md | 6 +- fp-cloud-cli/skill/references/commands.md | 2 +- fp-cloud-cli/tests/test_browser_login.py | 413 +++++++++++++++++ 16 files changed, 1521 insertions(+), 93 deletions(-) create mode 100755 __tests__/e2e/layout/fp-login.sh create mode 100644 fp-cloud-cli/tests/test_browser_login.py diff --git a/CHANGELOG.md b/CHANGELOG.md index da7e34b63..0a04233ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## 1.0.14-beta.0 — 2026-11-02 +### Features + +- `fp login` can sign you in from a browser, as `failproofai config` does: on a terminal it asks browser or email code, and either way you get your own session. New deliberate-run harness: `__tests__/e2e/layout/fp-login.sh`. + ### Dependencies - Replace Dependabot's #965 and #955, neither of which could install, and clear every fixable Dependabot alert in the TypeScript SDK's integration fixtures. `mastra-1` takes `@mastra/mcp` 2.7.0 with the `@mastra/core` 1.81.0 and `@mastra/memory` 1.40.0 it needs, `mastra-0` stays on Mastra 0.x and clears `@hono/node-server`, `systeminformation`, `glob` and `minimatch`, `deepmerge` leaves three fixtures through `html-to-text` 10.0.1, and the nested zod 3 leaves two. None of these lockfiles ship in a published package (#966) diff --git a/__tests__/e2e/layout/README.md b/__tests__/e2e/layout/README.md index 360a7d180..b79eef3ff 100644 --- a/__tests__/e2e/layout/README.md +++ b/__tests__/e2e/layout/README.md @@ -10,6 +10,7 @@ not depend on — so they are invoked deliberately. | `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), an older Cloud server without `/api/auth/cli/*` routes, 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) | +| `fp-login.sh` | an AgentEye stack (dashboard + mailpit + its containers), `uv sync` in `fp-cloud-cli`; optionally a Cloud with `config`'s login but not `fp`'s | `fp login`'s browser flow through a real pty: approve, the org picker, the email code from the menu, deny + retry, expiry, esc and ctrl-c, an approval nobody collects (no session), a dropped connection, opening the browser, Clouds without it (nothing minted), the network warning and when the email goes out, the person-side refusals, and no secret in any log | `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 @@ -38,6 +39,12 @@ bash __tests__/e2e/layout/systemd-service.sh DASH=http://localhost:3000 MAILPIT=http://localhost:8026 OLD_CLOUD=http://localhost:28080 PG_CONTAINER=agenteye-postgres-1 \ bash __tests__/e2e/layout/cli-login.sh +# fp-login.sh drives the real `fp` the same way. STACK is the compose project, which +# names the containers it reads. Add CLOUD_1090 and PG_1090 to cover a Cloud from +# before `fp`'s half of this; it stops and restarts the dashboard container once. +DASH=http://127.0.0.1:3000 MAILPIT=http://127.0.0.1:8026 STACK=agenteye \ + bash __tests__/e2e/layout/fp-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 index 45a465918..25239567c 100755 --- a/__tests__/e2e/layout/cli-login-driver.py +++ b/__tests__/e2e/layout/cli-login-driver.py @@ -1,16 +1,18 @@ #!/usr/bin/env python3 -"""Drive `failproofai config` through a real pseudo-terminal, screen by screen. +"""Drive a login 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. +Used by cli-login.sh for `failproofai config` (inside the systemd container, as the +unprivileged user) and by fp-login.sh for `fp login`. Both only offer 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