Repository navigation
test(dev): live ceremonies for GitHub, X and Google from the dev app - #72
Open
SupremaLex wants to merge 108 commits into
Open
SupremaLex wants to merge 108 commits into
SupremaLex wants to merge 108 commits into
Conversation
Runs the CCDP ceremony against the real Bridge, notary and CCDP, encodes the accepted proof as the GitHub verifier's TlsNotaryProof payload, and submits IdentityRegistry.bind from the user's wallet. It then reads the binding back from the registry and from the indexer. stack.ts starts anvil with the real libID-contracts v0.15.0 stack deployed by libid-deploy, a notary signing with the key that stack trusts, Bridge, CCDP and the usernames indexer. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
The live test signs in to GitHub with the test account (password and TOTP, ported from libid-server-rs' live ceremony suite), lets the ceremony notarize and prove in the browser, has an injected EIP-1193 wallet backed by an unlocked anvil account submit bind, and checks the transaction, the registry and the indexer through the page. Anvil mines a block every second so block time follows the clock: a proof's notary timestamp is checked against it. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
Biome skips the app's build cache as it does apps/dev's. The Bind GitHub anchor drops role=button, so it reads as the link it is. The GitHub login loop is split into one handler per page, under oxlint's complexity limit. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
pnpm -C ts/apps/bind test:live now starts the stack and app through Playwright's webServer, runs the test and stops them; the stack saves its container logs when LIBID_STACK_LOGS names a file. The Live end-to-end workflow runs it with the GitHub test account from repository secrets, fails rather than skips when they are missing, and keeps the trace, video and logs of a failed run. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
The app binds X as it binds GitHub: both are TLSNotary ceremonies with the same payload. The X test restores the saved session libid-server-rs' ceremony export writes, presents the browser as a person's Chrome with the stealth script and client hints ported from that suite, and approves the OAuth app. The live workflow passes the X secrets. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
The stack runs the keeper once after the deploy, so GoogleJwtRoots trusts Google's current keys through a notarized MPC-TLS reading; the notary opens its wire port for it. The app encodes the Google verifier's payload, whose client identifier is the token audience the result carries on its identity. The test restores the saved Google session and consents in the popup; X and Google share one saved-session loader. The nightly workflow takes the Google secrets. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
Pull requests from this repository get its secrets, so the suite can run on them as well as nightly; a fork's pull request is skipped. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
The runner context is not available in job-level env, which made the whole workflow file invalid. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
Keep both sides of the Biome ignore list, and regenerate the lockfile from main's with the bind app's dependencies. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
client.connect now generates the connection ID from a popup opened by PopupWindow.fromAnchor, and client.new takes no ceremony ID. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
Main's ceremony proves with the libid-circuits v0.6.0 circuits, whose verifiers chain-configurations v0.15.0 deploys. Under 0.14.0's verifiers every bind reverts with SumcheckFailed. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
The proof wait ends as soon as the page reports the ceremony failed, with its message, instead of running out its five minutes. Google's verification pages are caught by their challenge path and by text with either apostrophe. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
Google challenges the saved session when it arrives from a runner's address, so the test fails on every run there. It stays in the suite for local runs, and the workflow no longer reads the Google secrets. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
A Playwright trace records every fill and cookie, so the public artifact of a failed run held the GitHub test password and the saved sessions. CI records no trace or video, and a step refuses the upload when any file holds the password, the TOTP secret or a saved X cookie value. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
- local.ts holds the stack's addresses and ports for the stack, the app, the Vite and Playwright configs and the spec. - e2e/popup.ts drives a platform's pages until the popup leaves them, for GitHub, X and Google alike, and clicks a page-marked control. - LIBID_LIVE_PLATFORMS selects the platforms a run binds; CI binds GitHub and X, and the stack rotates Google's keys only when Google is bound. liveSecret fails a missing secret under LIBID_REQUIRE_LIVE everywhere. - The page reports one outcome, and the test waits on it instead of a hand-written loop that recognised only one terminal stage. - stack.ts keeps one chain client, drops a code check quoteBind already implies, takes needsRotation's ABI from @libid/contracts, and waits for Bridge and the indexer while the deploy runs. - The failure artifact uploads only screenshots, error notes and the stack log, after scan-secrets.ts finds no secret in them. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
…arted with - quoteBind and bind route on VERIFIER_VERSION, the CeremonyProofVerifier slot libid-deploy registers every launch verifier at (its LAUNCH_VERIFIER_VERSION, 1), instead of the ceremony version the proof reports. The two are different numbers that happen to agree at launch. - submit() takes the wallet and holder captured when the ceremony started, the holder its transaction data names, instead of re-reading the module's current ones. - The popup connection closes however the run ends, a rejection included. - A failed start reports its own error message rather than always blaming the Bridge configuration. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
- Before `up`, `compose down --volumes --remove-orphans` removes what an interrupted run of this checkout left, so the chain and the indexer's database start empty. - With any port the stack publishes (anvil, notary, Bridge, indexer API) still taken after that, startup refuses: the anvil check could pass against another checkout's chain and the deploy would go to it. - Once the stack is stopping, every wait rejects and no later step runs: no deploy, keeper or Vite server after Compose has exited; a Vite server created during a stop is closed instead of listening. - `down` reports when Docker cannot run it. - The deploy check also requires a verifier at VERIFIER_VERSION for every platform the run binds. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
After GitHub's error page the driver went back a page and cleared its "login filled" flag, and leaving github.com counted only with that flag set. The session was already signed in, so no login form came to set it again, and the redirect was never taken for success; going back could also leave github.com without any redirect. As in libid-server-rs' github.rs, the error page now reopens the authorization request the run started on, so the popup leaves github.com only through GitHub's redirect, and leaving it is success. The popup driver loses its `done` hook, which only GitHub used. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
- Dependabot's pull requests get no secrets; the job skips them as it skips forks. - Checkout keeps no credentials. - The test step has its own 45-minute timeout (stack start 15, two tests of 12, stop 2), inside a 55-minute job, so a hung run still reaches the secret scan and the upload. A test's timeout is 12 minutes: the popup driver's 3 and the page's 8-minute outcome wait. - The scan runs when the test step failed or timed out, not on a cancelled run, and the upload follows a clean scan. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
- drivePopup succeeds only once the popup requests Bridge's OAuth callback (local.ts BRIDGE + /auth/callback), seen as a navigation request so an immediate redirect onward still counts. Leaving the platform for another page keeps it waiting until its budget names the page; a Chrome error page or a popup closed before the return fails at once. - Waits inside a driver go through `pause`, which rejects with the driver's own reason when the wait would pass the 180 s budget, so GitHub's rate-limit and error-page backoffs report themselves instead of a generic timeout. The budget and the page's 8-minute outcome wait fit the 12-minute test timeout. - The page text reaches every driver lowercased with typographic apostrophes as plain ones; Google's own copy of that goes. - GitHub's authorize click has a 5 s timeout, ignores a failed click as X and Google do, and is not repeated within 5 s; the two-factor goto and the rate-limit reload ignore their errors, as github.rs does. - Session renewal hints say where libid-server-rs' `ceremony` lives: branch feat/live-ceremony-tests, libid-server-rs PR #12. stealth.js names presentAsPerson, which installs it. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
… agree on - The outcome is "bound" only when the registry resolves the identity to the holder the run started with and the indexer reports that holder; any other holder, or no indexer answer within 60 s, is a failure with its own message. - A ceremony that fails to start sets the outcome too, so the test ends on its message instead of waiting out the outcome timeout. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
- stack.ts takes .cache/stack.pid before touching the Compose project and refuses while another live stack.ts holds it, so a second run no longer tears down the first; a lock whose process is gone is stale. The lock also covers the CCDP build, which the running ccdp container mounts. - With LIBID_STACK_LOGS set, every child (the CCDP build, Compose with the containers' logs, libid-deploy, the keeper) writes to that file as it runs, not to our output, and the end-of-run `compose logs` goes. Under CI the Playwright web server drops the stack's stdout, so the public job log carries none of it. - Compose pulls every image, the keeper's included, before anything is timed, so a cold pull no longer eats the anvil wait. - libid-deploy is chosen by host (Linux or macOS, x86_64 or aarch64), each archive pinned by SHA-256, and a failed download reports its status instead of a digest mismatch. - Startup fails fast when local.ts, compose.yaml or keeper.toml disagree with local-dev.toml's [contracts] addresses, or bridge-config.toml does not admit local.ts' app origin. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
- Each pull request has its own concurrency group, a newer push cancelling the older run; scheduled and dispatched runs share another. A single group let one PR's pending run cancel another's. - Before the scan, any libid-bind Compose project still up is taken down, and the scan and the upload use one copy of the stack log, so nothing written after the scan goes up. - The artifact comment says what the scan does: it reads bytes, so a screenshot is safe because the pages driven never display a secret, and the job log carries none of the stack's output. - The X session comment says where `ceremony export x` lives. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
An AbortController replaces the stopping flag: waits end on it and commands the stack runs are terminated by it, so the startup sequence reads straight through instead of re-checking a flag between steps. The deploy tool downloads and CCDP builds while Docker clears the old stack and pulls, with the clean-up and the pull side by side. One helper probes Bridge and the indexer API, the ports are probed at once, the Bridge address comes from local.ts, the archive is unpacked from memory, and one fail() reports a refused start. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
The X and Google saved sessions live in session.ts, where the secret scan reads the same definitions the tests restore. clickFound owns the data-libid-click marking, so each driver gives only the control to find. GitHub's error-page and rate-limit back-offs share one helper, SameSite maps through a table, and the app reports a failed run through one fail(). Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
This was referenced Oct 6, 2026
ts/apps/bind becomes ts/apps/ceremony-live and @libid/bind becomes @libid/ceremony-live, ahead of the app dropping the chain: what it runs daily is the CCDP ceremony, which the ceremony package does not yet hand to `bind`. The Compose project prefix, the workflow's paths and biome's ignores follow. No behaviour changes. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
- Under CI the scan fails when it has no secret to look for, as a failure-output step given none of the job's secrets would. - settings.test.ts checks that each job's failure-output step is given every scanned secret (SCANNED) its test step is. - scan-secrets.test.ts runs the scan on logs holding fake markers: plain, URL-encoded and JSON-escaped values, a localStorage value, a session set but undecodable, the 8-character minimum, a clean log, and CI with nothing to look for. The dev test script runs every e2e/*.test.ts. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
…rows .gitignore ignores .env.test, *.env.test and .env.*.local everywhere; the README says to keep the env file outside the repository or name it .env.test, and describes LIBID_STACK_LOGS (appended, its path rule, required under CI), CI's effect on the job log, and an empty LIBID_LIVE_PLATFORMS. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
- paths.ts holds the path rule (a relative path is the env file's neighbour, else relative to where pnpm was invoked); settings.ts and services.ts both resolve through it, so LIBID_STACK_LOGS means the same file in `pnpm dev` and `test:live`. - A Lookup returns a value as set, empty included; settings.ts treats empty as absent itself, so an injected lookup can express "set but empty" for LIBID_LIVE_PLATFORMS without reading process.env. - loadEnvFile: an exported value wins over the env file; an exported empty value counts as unset, except LIBID_LIVE_PLATFORMS, where it selects no platform. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
- The scan read sessions with its own parser, which missed the capitalised `Value` spelling cookies.rs accepts: a log holding such a value passed. It now reads every cookie through session.ts' exportCookies, with no host or expiry filter, plus storage-state localStorage values; text that is no export falls back to its "value" strings, the key in any case. - The scanned variables are settings.ts' SCANNED, one list; a test sets each in turn and checks the scan finds its marker, and that a variable outside it is not looked for. - A found secret exits 2 and nothing to look for under CI exits 3, so the tests tell them from a crash (1); the workflow fails on any. - storedOf checks the optional fields' types as cookies.rs does (path, secure, httpOnly, sameSite, expires, partition key): a wrong type makes the export unreadable, never a TypeError. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
…t rule - The TOTP step reads the clock once for its step and code, and counts its form showing again as a refusal only 5 s after the submit and in a later step, so a slow redirect is not a refusal. - GitHub pages route by their known paths before the 2FA checkup's text, which the TOTP page could otherwise match. - The X driver recognises X's pages with session.ts' onX, the Rust suite's x_host; cookies are still set on x.com and twitter.com, as the Rust suite sets them. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
- watchAppFailure lets the spec tell drivePopup when the app's run has failed; the driver then stops with the run's own message instead of waiting out its budget on the platform. - The spec uses app.fixtures.ts' launch, newestRun and a new expectReady (openApp uses it too), and watches popups for their return with a context 'page' listener added before the click, not a waitForEvent predicate with a side effect. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
- preflight() runs in the runner process at config load: the settings, then under LIBID_REQUIRE_LIVE each selected platform's saved session and the GitHub TOTP key, so a bad one fails in seconds. - With no platform selected the config starts no webServer. - With LIBID_STACK_LOGS the webServer appends the build's output to it too, so under CI a failed build is in the scanned, uploaded log rather than lost with the ignored stdout. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
Each job's timeout-minutes must be at least its test step's plus a stated 10 minutes for checkout, install, the browser install, any proxy and the failure-output step. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
- Both live jobs share a job-level concurrency group across all runs (live-e2e-accounts, never cancelled): overlapping runs could submit the same TOTP code within one 30-second window. Pull request runs still cancel their own older run. GitHub keeps one pending job per group, so a newer pending job replaces an older pending one; the comment says so. - Pull requests trigger the workflow only for what a live ceremony runs: the dev app, the ceremony, popup and ledger packages, their build script and brand/ styles, the workspace setup, and the workflow and its two actions. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
- The live webServer's environment sets every account and session variable (settings.ts' table, outside tooling) to empty: services.ts, the build and the containers get none of the test accounts' secrets. The secret scan stays as a backstop. - The stack starts only when a test will run: a selected platform whose settings are all present (runnablePlatforms). A run that skips every test neither builds nor starts it. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
A *_COOKIES_FILE the scan cannot read now fails it (exit 4), naming the variable but not the path or anything in it, instead of being skipped. The scan also loads the file LIBID_TEST_ENV_FILE names, as the config does, so a session file set there is scanned and resolved by the same path rule. Both have tests. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
- The failure-output action stops the stack best effort: a failed `docker compose down` no longer aborts the step before the scan and the upload. The scan's failure stays fatal. - `node services.ts --project` prints the checkout's Compose project, which the action stops, instead of repeating its libid-dev prefix. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
With --app, services.ts also probes APP_ORIGIN's port before starting, beside compose.yaml's published ports. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
A saved Google session holds a session only with LSID or __Host-1PLSID on accounts.google.com, as libid-server-rs' google.rs signed_in has it, rather than SID or __Secure-*PSID; preflight checks it the same way. The X rule stays x.rs' signed_in: an auth_token. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
As the Rust driver does, "Something went wrong" on a page other than the consent, login or /account/access ones fails the run, naming the path. X holding the account at /account/access for more than 30 s, the Rust suite's wait, fails with a named error. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
- When the code's POST target, /sessions/two-factor, shows a failure, the driver keeps GitHub's flash message before going back to the code form, and the refusal error carries it. - After filling six digits the driver waits up to 3 s for GitHub's own submit and presses the button only if the form is still there, so one code is not sent twice. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
- drivePopup races the app-failure check, as well as each step, against its budget. - budgets.ts lists the bounded steps one test performs (page load, Ready, the launch click, the popup, the run's id, the driver, the outcome, the row's message): 15 minutes; TEST is 16. settings.test.ts requires TEST to exceed their sum, and the CI step timeouts' comments follow (60 and 28 minutes, within 65 and 35). Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
The live tests had grown guards and drift checks around a small core. This keeps the core and drops the rest: - settings.ts: each platform's variables (the _COOKIES/_COOKIES_FILE alternates included), the env file, LIBID_LIVE_PLATFORMS checked, one "missing" error under LIBID_REQUIRE_LIVE, and the runnable platforms that decide whether the stack starts. - session.ts: decode a saved session without echoing the parser's message, keep the platform's hosts, check one signed-in cookie per platform (X auth_token; Google LSID or __Host-1PLSID on accounts.google.com), and map to addCookies. - The stack's environment is an allowlist (PATH, HOME, USER, TMPDIR, LANG, CI, PNPM_HOME, XDG_*, DOCKER_*; Playwright merges its own, so everything else is set empty): no test account's secret, the Rust suite's passwords included, reaches the build, services.ts or the containers. - github.ts: one TOTP per 30-second step, each code submitted once, the login filled once, the 2FA checkup skipped; the reference-vector test stays. - services.ts: LIBID_STACK_LOGS (appended) and the refusal to start on a taken port, compose's published ones and the app's. - The X and Google drivers are back to their first port; X pages are recognised with session.ts' onX. Removed: the secret scan and its tests, preflight, the shared path and budget modules, the settings/README/workflow drift tests, the typo warning, the notary health probe, services.ts --project and its compose-port checks, per-field cookie validation and the __Host- url branch. BREAKING CHANGE: LIBID_STACK_LOGS is no longer required under CI, and the scan-secrets script is gone. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
Two jobs with plain steps: GitHub and X in one, Google through the SSM proxy in the other, each given only its platforms' secrets and its own concurrency group, so neither cancels the other's pending run. On a failure a job stops any stack left running, prints the end of the stack log to the job log, where GitHub masks secrets and the stack holds none, and uploads the screenshots for 7 days. The failure-output action and its scan are removed. Each job states its timeout arithmetic. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
The drivers' injected page scripts give way to locators: X's consent button by test id or role, its cookie banner by role (tried until it is accepted), Google's account row by data-identifier or its Continue or Allow button, and Google's login check by visible inputs. One throttledClick in popup.ts, at most a click every 5 s on the first visible match, replaces GitHub's, Google's and X's own timers. The app-failure check runs every 2 s. TOTP generation keeps only the options otpauth does not default, and the renew messages drop the branch name. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
- LIBID_LIVE_PLATFORMS set means every listed platform must have its variables (one error names those missing); unset, every platform with its variables runs and the rest are skipped. LIBID_REQUIRE_LIVE is gone. Alternate variable names are lists, not an `A|B` string. - Saved sessions restore with a plain map: no twitter.com copy of X's cookies. A partition key in the Rust export's CDP object form maps to its top-level site. - The spec checks the run is accepted for the expected platform and account; the ceremony already validates the proof, the nodes, the ids and the expiry. The row's message is read only for a run that was not accepted. BREAKING CHANGE: LIBID_REQUIRE_LIVE is removed; set LIBID_LIVE_PLATFORMS to require platforms. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
- With LIBID_STACK_LOGS the live webServer command redirects all of its output there (`exec >>"$LIBID_STACK_LOGS" 2>&1`), the build's included; services.ts writes to its inherited output again, and the one path rule stays settings.ts'. - services.ts no longer probes the app's port: Vite's strictPort and Playwright already refuse a taken one. - local.ts gains APP_PORT and BRIDGE_CONFIG, used by vite.config.ts, services.ts' readiness check and app.fixtures.ts; app.spec.ts and app.ts use NOTARY and BRIDGE directly. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
The failure step only prints the end of the stack log: the test step stops its own stack. LIBID_REQUIRE_LIVE is gone (each job lists its platforms), both jobs exclude forks and Dependabot the same way, and each job's timeout carries its arithmetic in one comment. The README follows, and .gitignore drops a pattern *.env.test already covers. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
Pull requests no longer run it; the proxy role trusts this workflow on main only. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
Google trusts a saved session only from the address it was signed in from, so it is made by hand in plain Chrome through CI's proxy and exported with e2e/export-session.ts; the expired-session error points there. Assisted-by: Claude Opus 5.5 Signed-off-by: SupremaLex <georglutsenko@gmail.com>
SupremaLex
marked this pull request as ready for review
October 23, 2026 15:49
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Live end-to-end tests that prove real GitHub, X and Google identities from the dev app's UI, against the real platforms, notary and Bridge. No chain is involved.
What it adds
ts/apps/dev/e2e/, run withpnpm --filter @libid/dev test:live(playwright.live.config.ts). The config starts the dev app's own stack (pnpm dev), clicks the platform in the UI, drives the popup through the platform's sign-in and consent, and checks the run is accepted for the expected platform and account. Proof contents are left to@libid/ceremony, which validates them before the app seesaccepted.github.tssigns in with username, password and TOTP, one code per 30-second step and each submitted once;x.tsandgoogle.tsrestore a saved session and only consent;popup.tsdrives the popup and notices its return to the Bridge, or the app's own failure.settings.ts): the same variable names as libid-server-rs' ceremony-tests, so one.env.testserves both suites.LIBID_LIVE_PLATFORMSlists the platforms to prove, and each one listed must have its variables. The README has the table.local.tsholds the app, Bridge and notary origins;services.tsrefuses to start when the stack's ports are already in use.Google's session: a manual first step
Google challenges a saved session used from an address other than the one it was signed in from. It also refuses sign-in in an automated browser. So CI never signs in to Google; it reuses a session a person made:
aws ssm start-session … AWS-StartPortForwardingSession).--proxy-serverpointing at that tunnel.node e2e/export-session.ts <profile> google.json.base64 google.jsonas theGOOGLE_TEST_ALICE_COOKIESsecret, and delete the file and the profile.Steps are in
ts/apps/dev/README.md("Google's session"). Redo them when the Google job reports an expired session, or when the proxy's address changes. X's session is likewise saved once (ceremony export x); GitHub signs in on every run.CI (
.github/workflows/live-e2e.yml)Not a required check.
LIBID_GOOGLE_RUNNER=ssm. It assumesLIBID_GOOGLE_PROXY_ROLEover OIDC, opens an SSM port-forward to a Squid proxy on an EC2 instance (LIBID_GOOGLE_PROXY_INSTANCE) with no inbound ports, and sends the browser through it, so Google sees the address the session was signed in from.The proxy's Terraform currently lives outside this repository (a sandbox AWS account). Where it is deployed for good is still open; the workflow only needs the two variables and the role's OIDC trust.
Verified
Known limits
person.tsgives the X and Google browser a desktop user agent and installsstealth.jsfor the whole context, so the app and prover pages run with it too.