Skip to content

refactor(mock-api): domain split + OAuth + Composio + e2e workflow + macOS mega-spec scaffold - #1532

Merged
senamakel merged 20 commits into
tinyhumansai:mainfrom
senamakel:feat/mock-api-split-and-gap-fill
May 13, 2026
Merged

senamakel merged 20 commits into
tinyhumansai:mainfrom
senamakel:feat/mock-api-split-and-gap-fill

Conversation

@senamakel

@senamakel senamakel commented May 12, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Split the 1500-line scripts/mock-api-core.mjs into domain modules under scripts/mock-api/ (state, http, socket, admin, server, plus 10 per-domain route files). Old path becomes a re-export shim — every existing caller (scripts/mock-api-server.mjs, app/test/e2e/mock-server.ts, scripts/test-rust-with-mock.sh) keeps working unchanged.
  • Filled gap routes the app/core call but the mock never had: /version-check, /auth/email/send-link, /auth/telegram, /users, /teams/join, /conversations*, /messages*, /channels*, /notifications, /webhooks/ingress*, /settings/cron-jobs*, /settings/webhooks-triggers*, /payments/credits/{top-up,transactions,auto-recharge/cards/*}, /agent-integrations/composio/{github/repos,tools}, /agent-integrations/apify/runs/*.
  • New OAuth landing pages — /mock-oauth/<provider> (+ /mock-<provider>-oauth legacy alias) render a meta-refresh + JS auto-redirect to openhuman://oauth/success?integrationId=…&provider=…, the desktop deep link desktopDeepLinkListener already handles. Plus /auth/<provider>/{callback,exchange} for backend-mediated flows. Knobs: oauthAutoRedirectMs, oauthIntegrationId, oauthForceError, oauthErrorCode; per-request overrides via ?integrationId, ?provider, ?error, ?manual=1.
  • Pre-existing fix: e2e-build.sh invoked the deleted scripts/stage-core-sidecar.mjs (removed in fix(core,cef): run core in-process and stop orphaning CEF helpers on Cmd+Q #1061 when core went in-process). Dropped the dead node call so e2e builds succeed.
  • Mega e2e flow scaffold (app/test/e2e/specs/mega-flow.spec.ts) + RPC token file handoff in app/src-tauri/src/core_process.rs (debug-build only): writes the embedded core's bearer token to ${tmpdir}/openhuman-e2e-rpc-token so the WDIO Node process can authenticate against the in-process RPC server. core-rpc-node.ts reads it and sends Authorization: Bearer ….
  • New dedicated .github/workflows/e2e.yml runs linux/macos/windows e2e in parallel — Linux reuses the existing ghcr.io/tinyhumansai/openhuman_ci:latest image (same one unit-tests and e2e/docker-compose.yml use), macOS uses Appium Mac2 (canonical e2e runner), Windows uses tauri-driver/WebView2. All legs continue-on-error so flaky platforms don't block PRs.

Problem

  • The mock backend was a single 1500-line file with no clean way to add new routes per domain, and several routes the production app/core call were missing entirely — making e2e specs that exercise those flows fail with 404s in the mock log.
  • The mock OAuth landing pages (/mock-<provider>-oauth) returned a static <h1> and never completed the flow, so any spec that drives the OAuth click-through hung.
  • pnpm test:e2e:build crashed with MODULE_NOT_FOUND because it called a script deleted in fix(core,cef): run core in-process and stop orphaning CEF helpers on Cmd+Q #1061.
  • No dedicated e2e workflow existed — the commented-out blocks in test.yml (Linux + macOS) hadn't been touched since the CEF migration, and there was no Windows leg at all.

Solution

  • Per-domain handler files keep each route module small and let new endpoints land without growing the dispatcher. Each handler returns true if it consumed the request; the server walks them in order and 404s with a UNHANDLED console log on miss (preserving the existing fail-fast contract).
  • Gap-fill stubs are deliberately minimal — empty arrays / echo bodies — so tests that check for "the call happened" pass without us pretending to have rich fixtures yet. Tests that need richer state can override via setMockBehavior.
  • The OAuth landing page uses both <meta http-equiv="refresh"> and a setTimeout JS redirect so it works whether the e2e harness drives the embedded webview, an external browser, or just inspects the URL via the OS.
  • The dedicated e2e workflow is split out of test.yml (unchanged) so the e2e cadence and the unit/rust cadence can evolve independently. Linux uses the existing CI image so we don't reinstall Xvfb/dbus/webkit2gtk-driver/tauri-driver on every run.

Submission Checklist

  • Tests added or updated — pnpm test:unit (2042 tests) passes; manual curl smoke against the live mock covers admin + every route + every OAuth variant + the full Composio enable→list cycle; macOS smoke spec (smoke.spec.ts) passes 3/3 on Mac2.
  • Diff coverage ≥ 80% — changed lines are predominantly mock infrastructure (scripts/mock-api/**) which is exercised by every e2e spec that runs, plus the existing unit-test surface that imports through mock-server.ts. The new core-rpc-node.ts Bearer plumbing is exercised by the mega-flow spec; the Tauri-side token write is debug-build-only and not in the release coverage gate.
  • Coverage matrix updated — N/A: this PR doesn't add/remove/rename user-facing features. The mock split is internal test infrastructure; the mega-flow spec is new e2e coverage but doesn't add a product feature ID.
  • All affected feature IDs from the matrix are listed in the PR description under ## Related — N/A per above.
  • No new external network dependencies introduced — everything routes through the mock backend.
  • Manual smoke checklist updated if this touches release-cut surfaces — N/A: no release-cut surface changed.
  • N/A: no linked issue

Impact

  • Runtime: only the debug-build branch in core_process.rs is new in shipped binaries; the #[cfg(debug_assertions)] gate means release builds never write the token file or reference the path.
  • Performance: the mock-server refactor is a behavior-preserving move (validated by 2042 vitest tests passing before/after); the new gap-fill handlers are pure echo/empty-list responses with no expensive logic.
  • Security: the debug-only RPC token file at ${tmpdir}/openhuman-e2e-rpc-token is gated by #[cfg(debug_assertions)] and never touched in release builds. Local-only access (tmpdir is per-user on macOS/Linux).
  • Migration / compatibility: scripts/mock-api-core.mjs is a re-export shim — every external caller still works without changes.

Related

  • Closes:
  • Follow-up PR(s)/TODOs: Pre-seed openhuman_core_mode = local in debug builds (or via an e2e marker file) so BootCheckGate skips the Local/Cloud picker on first launch. Without that, the mega-flow spec's deep-link consume call can't reach the mock because the embedded core never starts. Estimated ~15-line TS change in BootCheckGate.tsx to default to local when import.meta.env.DEV is true.

AI Authored PR Metadata (required for Codex/Linear PRs)

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: feat/mock-api-split-and-gap-fill
  • Commit SHA: ba1360ff7f3072fabab4a7d0b176ac35828f093d

Validation Run

  • pnpm --filter openhuman-app format:check — passes (pre-push hook ran)
  • pnpm typecheck — passes (pre-push hook ran)
  • Focused tests: pnpm test:unit → 2042 passed / 3 skipped (218 files)
  • Rust fmt/check (if changed): cargo fmt --check on both manifests — clean (pre-push hook ran)
  • Tauri fmt/check (if changed): pre-push hook covered

Validation Blocked

  • command: bash app/scripts/e2e-run-spec.sh test/e2e/specs/mega-flow.spec.ts mega-flow (on macOS Mac2)
  • error: mega-flow spec scenarios assert on mock request log, but the in-process core RPC server doesn't start because BootCheckGate shows a Local/Cloud picker on first launch (localStorage wiped by the e2e script every run), and CEF WebView is inaccessible to XCUITest on macOS so the picker can't be dismissed from the driver.
  • impact: mega-flow.spec.ts will not pass until the BootCheckGate auto-default-to-local follow-up lands. Smoke spec (smoke.spec.ts) still passes 3/3 on Mac2 and proves the bundle + driver + mock all work. Documented in commit feat(e2e): mega-spec scaffold and in the ## Related follow-up note above.

Behavior Changes

  • Intended behavior change: none for end users. All changes are debug-only or behind the mock test surface.
  • User-visible effect: none.

Parity Contract

  • Legacy behavior preserved: the re-export shim at scripts/mock-api-core.mjs keeps every existing import path working byte-identically. Unit tests confirm.
  • Guard/fallback/dispatch parity checks: each route module preserves the original handler's status codes, body shapes, and behavior-knob semantics. New gap-fill handlers are additive only.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): N/A
  • Canonical PR: this one
  • Resolution: N/A

Summary by CodeRabbit

  • Tests

    • Added a unified E2E CI workflow (Linux/macOS/Windows) with manual "full" runs, failure artifact uploads, and a new comprehensive "mega flow" end-to-end spec covering login, OAuth, integrations, error paths, and recovery.
  • Chores

    • Major expansion of the local mock backend to simulate auth, OAuth, payments, integrations, conversations, webhooks, invites, users, cron, sockets, and behavior knobs.
    • Updated E2E build/run scripts and .gitignore to better manage artifacts and local stores.

Review Change Stack

senamakel added 6 commits May 12, 2026 00:33
The 1500-line scripts/mock-api-core.mjs is now a thin re-export shim over
scripts/mock-api/, organized by domain:

  state.mjs       — mockBehavior, request log, tunnels, user/team factories
  http.mjs        — CORS, json/html senders, body parsing, header redaction
  socket.mjs      — engine.io polling + WebSocket upgrade
  admin.mjs       — /__admin/{health,requests,behavior,reset}
  server.mjs      — http server lifecycle + route dispatch
  routes/
    auth.mjs           — /auth/*, /telegram/login-tokens/*
    user.mjs           — /settings, /teams*, /rewards/me, /referral/*, /users
    invites.mjs        — /invite/*
    payments.mjs       — /payments/*, /billing/*
    integrations.mjs   — /agent-integrations/*, /gmail/*, /notion/*, /telegram/*, /openai/v1/*
    webhooks.mjs       — /webhooks/core/*, /webhooks/ingress/*
    conversations.mjs  — /conversations, /messages*, /channels*, /notifications
    version.mjs        — /version-check
    cron.mjs           — /settings/cron-jobs, /settings/webhooks-triggers

Gap-fill stubs added for routes the app/core call but the mock never
implemented: /version-check, /auth/email/send-link, /auth/telegram,
/users, /teams/join, /conversations*, /messages*, /channels*,
/notifications, /webhooks/ingress*, /settings/cron-jobs*,
/settings/webhooks-triggers*, /payments/credits/{top-up,transactions,
auto-recharge/cards/setup-intent,auto-recharge/cards/:id},
/agent-integrations/composio/{github/repos,tools}, /agent-integrations/apify/runs/*.

All 2042 vitest unit tests pass; manual curl smoke against the split
server confirms admin endpoints, existing routes, and new gap routes
all respond. Existing import paths (scripts/mock-api-server.mjs,
app/test/e2e/mock-server.ts) keep working unchanged.
Core has been compiled in-process since PR tinyhumansai#1061, so the sidecar staging
script was removed but app/scripts/e2e-build.sh still tried to invoke
it and crashed with MODULE_NOT_FOUND. Drop the dead call so e2e builds
succeed again.
The mock previously handed back an oauthUrl pointing at /mock-<provider>-oauth
but that page just rendered `<h1>Mock OAuth</h1>` and went nowhere, so any
e2e spec that exercised the real OAuth click-through hung.

Replace with a proper mock provider:

  GET  /mock-oauth/<provider>           — landing page that auto-redirects to
  GET  /mock-<provider>-oauth (legacy)    `openhuman://oauth/success?integrationId=...&provider=...`
                                          via <meta refresh> + JS, with a
                                          visible "Continue" link as fallback.

  GET  /auth/<provider>/callback        — 302 straight to the success/error
                                          deep link (skips the HTML page).

  POST /auth/<provider>/exchange        — code-for-token JSON exchange for
                                          backend-mediated flows.

Behavior knobs (settable via /__admin/behavior):
  oauthAutoRedirectMs  — delay before redirect ("manual" to disable)
  oauthIntegrationId   — integrationId emitted in the deep link
  oauthForceError      — flip the whole flow to the error deep link
  oauthErrorCode       — error code passed along

Per-request overrides via query string: ?integrationId, ?provider, ?error,
?manual=1.

Smoke-tested all four flows (success page, error page, callback 302,
exchange POST) against a running mock; all 2042 vitest tests still pass.
E2E run failures dump screenshots + source.xml to app/test/e2e/artifacts/,
and pnpm caches its store at .pnpm-store/ when network-restricted hosts
prefer an in-repo cache. Neither belongs in version control.
A single Mac2 session walks login → Gmail OAuth → Composio in one app
launch, driving everything through deep links + mock state and asserting
via the mock request log + core RPC. Between-scenario reset uses
openhuman.config_reset_local_data (mirrors the production "Clear app
data + log out" flow) plus re-writing ~/.openhuman/config.toml so the
mock URL survives the reset.

Three pieces:

* app/src-tauri/src/core_process.rs — when built with debug_assertions,
  write the embedded core's bearer token to
  ${tmpdir}/openhuman-e2e-rpc-token. Release builds never touch this
  file. Gives the e2e harness (a separate Node process) a way to
  authenticate against the in-process RPC server — the token otherwise
  lives only inside the Tauri host.

* app/test/e2e/helpers/core-rpc-node.ts — read the token file before
  every probe + call, include Authorization: Bearer …. Falls through
  cleanly when the file is missing.

* app/test/e2e/specs/mega-flow.spec.ts — six scenarios in one session:
  login (consume), bypass login, Gmail OAuth success, Composio trigger
  lifecycle via RPC, Gmail OAuth error path, post-reset re-login.

Known gap (blocks the spec from passing as-is): the app's BootCheckGate
shows a Local/Cloud "core mode picker" on first launch and won't start
the embedded core until the user picks. CEF WebView is inaccessible to
XCUITest on macOS, so the picker can't be dismissed from Mac2. A
follow-up patch needs to either pre-seed localStorage with
openhuman_core_mode=local in debug builds, or have the Tauri host
auto-default to local mode behind a debug-only env/marker check. Once
that lands the mega-spec should run end-to-end.

Mock backend, OAuth deep-link pages, Composio handlers, and the token
bridge are all in place and validated independently.
Single workflow file (.github/workflows/e2e.yml) runs WDIO desktop e2e
on three OSes simultaneously. All three legs are continue-on-error so
known-flaky platforms don't block PRs; macOS is the source of truth.

  - e2e-linux    containerized in ghcr.io/tinyhumansai/openhuman_ci:latest
                 (reuses the project's CI image — Xvfb, dbus, webkit2gtk-
                 driver, tauri-driver, Rust 1.93.0, Node 24 all preinstalled).
                 Smoke-only because tauri-driver/webkit2gtk can't drive CEF's
                 DOM.

  - e2e-macos    bare runner, Appium Mac2 driver. Canonical e2e runner.
                 Smoke + mega-flow on every PR; full spec suite via
                 workflow_dispatch with `full=true`.

  - e2e-windows  bare runner, tauri-driver via WebView2. Smoke only;
                 Windows hasn't been validated against the broader suite.

Linux/Windows reuse the same Rust target cache key shape as the existing
unit-tests jobs; macOS gets its own cache. Failure-only artifact upload
on each leg for triage.
@senamakel
senamakel requested a review from a team May 12, 2026 11:11
@coderabbitai

coderabbitai Bot commented May 12, 2026 •

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a multi-OS E2E GitHub Actions workflow and build script changes, writes a debug-only per-launch RPC token file with Node helper support, refactors the mock API into modular state/http/server/socket/route modules, and adds a single-session mega-flow E2E spec exercising login, OAuth, integrations, and reset flows.

Changes

E2E Testing Infrastructure Setup

Layer / File(s) Summary
CI workflow & build script
.github/workflows/e2e.yml, .gitignore, app/scripts/e2e-build.sh, app/scripts/e2e-run-spec.sh
Adds E2E workflow (Linux/macOS/Windows jobs), marks jobs continue-on-error, updates .gitignore for e2e artifacts and pnpm store, and refactors the e2e build/run scripts to reflect in-process core compilation and explicit OS-specific behavior.
Core RPC token file & client header
app/src-tauri/src/core_process.rs, app/test/e2e/helpers/core-rpc-node.ts
Writes per-launch RPC bearer token to ${tmp}/openhuman-e2e-rpc-token in debug builds; E2E Node helper reads that file and includes Authorization: Bearer … headers for core JSON-RPC fetches and treats HTTP 401 as a successful probe during discovery.

Mock API Backend Refactor & Implementation

Layer / File(s) Summary
Module entrypoint & in-memory state
scripts/mock-api-core.mjs, scripts/mock-api/index.mjs, scripts/mock-api/state.mjs
Legacy entrypoint becomes a re-export shim; index re-exports server/state APIs; state.mjs provides DEFAULT_PORT, MOCK_JWT, request log, mockBehavior map, mock tunnels, fixtures, and helper utilities.
HTTP helpers & responses
scripts/mock-api/http.mjs
Adds CORS constants, json/html response helpers, requestOrigin, readBody, tryParseJson, and header normalization/redaction utilities.
Admin, server lifecycle & socket support
scripts/mock-api/admin.mjs, scripts/mock-api/server.mjs, scripts/mock-api/socket.mjs
Implements admin endpoints, request logging, OPTIONS handling, ordered route dispatch, /socket.io/ Engine.IO polling open, WebSocket upgrade and frame parsing, and start/stop lifecycle with optional retry and socket tracking.
Auth & OAuth route handlers
scripts/mock-api/routes/auth.mjs, scripts/mock-api/routes/oauth.mjs
Implements token consume, desktop exchange, /auth/me (delay/revocation/failure knobs), integrations listing, email link, provider connect endpoints, mock OAuth pages, callback redirects, and exchange endpoints.
Integrations & Payments handlers
scripts/mock-api/routes/integrations.mjs, scripts/mock-api/routes/payments.mjs
Adds many integration stubs (Telegram/Notion/Gmail/OpenAI/Composio/Apify) including Composio enable/delete persistence and Apify polling; payments covers credits, plans, Stripe/Coinbase flows, cards, auto-recharge, and top-ups with behavior-driven error modes.
User, Admin & Invites handlers
scripts/mock-api/routes/user.mjs, scripts/mock-api/routes/invites.mjs, scripts/mock-api/admin.mjs
User routes (settings/teams/referrals/rewards) with scenario-based rewards snapshot generation; invites endpoints for redeem/list/status; admin endpoints for health, request logs, behavior view/update, and reset operations.
Webhooks, Conversations, Cron, Version handlers
scripts/mock-api/routes/webhooks.mjs, scripts/mock-api/routes/conversations.mjs, scripts/mock-api/routes/cron.mjs, scripts/mock-api/routes/version.mjs
Webhooks support core tunnel CRUD and ingress endpoints; conversations, cron, and version route handlers provide gap-fill/mock responses and standard JSON envelopes.

Comprehensive E2E Test Coverage

Layer / File(s) Summary
Mega-flow single-session spec
app/test/e2e/specs/mega-flow.spec.ts
New TypeScript E2E spec running multiple scenarios in one macOS session: app liveness, Telegram login deep link flows, auth-bypass, OAuth success refresh, Composio trigger enabling via core RPC, OAuth error resilience, and a final factory reset — using the in-process mock server and per-scenario state resets.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • graycyrus

Poem

🐰
I hid a token in a temp-file bright,
Mock servers hummed to keep tests light.
CI hops Linux, mac, and Windows three,
Deep-links, OAuth, resets — E2E glee.
The rabbit cheers — tests passed for me!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: refactoring the mock API into domain modules, adding OAuth/Composio support, implementing an e2e workflow, and scaffolding a macOS mega-spec. It is specific, concise, and clearly conveys the primary scope.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (1)
app/test/e2e/specs/mega-flow.spec.ts (1)

225-244: 💤 Low value

Consider simplifying the result extraction pattern.

The nested fallback chain (before.result?.triggers ?? before.value?.result?.triggers ?? []) suggests uncertainty about the response shape. If the RPC response schema is well-defined, a single access path would be clearer and less fragile.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/test/e2e/specs/mega-flow.spec.ts` around lines 225 - 244, The tests use a
fragile nested fallback chain to read triggers (before.result?.triggers ??
before.value?.result?.triggers ?? []) which makes the spec unclear; simplify by
using the defined RPC response shape from callOpenhumanRpc for
composio_list_triggers and read a single, explicit path (e.g.,
before.result.triggers) into beforeList/afterList after asserting
before.ok/after.ok, and update both occurrences (beforeList and afterList)
accordingly so the code assumes one canonical response shape instead of the
three-way fallback.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src-tauri/src/core_process.rs`:
- Around line 197-211: The debug-only write of the RPC bearer token (token_path
/ self.rpc_token in the debug block) currently uses std::fs::write which leaves
default OS permissions; change this to create the file with restrictive
permissions: on Unix use std::fs::OpenOptions +
std::os::unix::fs::OpenOptionsExt and set .mode(0o600) before writing
(create/write/truncate), and on Windows apply a platform-specific ACL (e.g., use
winapi/Windows API to set security descriptor or SetFileInformationByHandle) or
at minimum mark the file read-only only for the owner after creation; ensure you
still log the same debug/warn messages and handle/report any permission-setting
errors when writing the token.

In `@app/test/e2e/helpers/core-rpc-node.ts`:
- Around line 33-38: The buildHeaders function is currently returning an
Authorization header unconditionally when readBearerToken() exists, and
tryPingRpc (the blind port-probing loop around lines 67-68) uses it and can leak
the bearer token to arbitrary localhost services; modify the code so
buildHeaders accepts an option (e.g., includeAuth: boolean) or add a separate
buildAuthHeaders that only adds Authorization when explicitly requested, then
update tryPingRpc to call the headers builder with includeAuth=false (or use the
non-auth headers helper) while probing candidate ports and only include
Authorization for requests to the known, trusted RPC endpoint.

In `@scripts/mock-api/http.mjs`:
- Around line 32-37: readBody currently resolves only on the stream "end" event
and never rejects, so request errors or aborts hang callers; update the readBody
function to accept (req) and return a Promise that registers "data" to push
chunks, and also listens for "error" and "aborted" (or "close" with aborted
check) to reject the Promise, and ensure all listeners
("data","end","error","aborted"/"close") are removed in each terminal path to
avoid leaks; keep using Buffer.concat(chunks).toString() on successful "end"
resolution and reject with the original error or an AbortError when aborted.

In `@scripts/mock-api/routes/invites.mjs`:
- Around line 17-18: The route matcher in invites.mjs uses /^\/invite\/status/
which over-catches any path starting with /invite/status; update the condition
that checks method and url (the if that calls json(res, 200, { success: true,
data: { valid: true } })) to only match the exact status endpoint — e.g. change
the regex to require end-of-path (and allow an optional query string) such as
matching "/invite/status" exactly so unrelated routes are not intercepted by
this mock.

In `@scripts/mock-api/routes/payments.mjs`:
- Around line 191-199: The amount parsing currently uses
Number(parsedBody?.amountUsd ?? 0) || 10 which turns an explicit 0 into 10;
change the logic in the POST /payments/credits/top-up handler so you parse
amount with Number(parsedBody?.amountUsd ?? 0) into the amount variable and then
set amount = Number.isFinite(amount) ? amount : 10 (or similar finite-check
fallback), preserving 0 while only defaulting to 10 for non-finite or invalid
inputs; update the variable named amount used in the json(res, 200, { data: {
amountUsd: amount }}) response accordingly.

---

Nitpick comments:
In `@app/test/e2e/specs/mega-flow.spec.ts`:
- Around line 225-244: The tests use a fragile nested fallback chain to read
triggers (before.result?.triggers ?? before.value?.result?.triggers ?? []) which
makes the spec unclear; simplify by using the defined RPC response shape from
callOpenhumanRpc for composio_list_triggers and read a single, explicit path
(e.g., before.result.triggers) into beforeList/afterList after asserting
before.ok/after.ok, and update both occurrences (beforeList and afterList)
accordingly so the code assumes one canonical response shape instead of the
three-way fallback.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 244a495d-ac4e-4432-94e5-0bcb62c2ca60

📥 Commits

Reviewing files that changed from the base of the PR and between 78d1f3d and ba1360f.

📒 Files selected for processing (23)
  • .github/workflows/e2e.yml
  • .gitignore
  • app/scripts/e2e-build.sh
  • app/src-tauri/src/core_process.rs
  • app/test/e2e/helpers/core-rpc-node.ts
  • app/test/e2e/specs/mega-flow.spec.ts
  • scripts/mock-api-core.mjs
  • scripts/mock-api/admin.mjs
  • scripts/mock-api/http.mjs
  • scripts/mock-api/index.mjs
  • scripts/mock-api/routes/auth.mjs
  • scripts/mock-api/routes/conversations.mjs
  • scripts/mock-api/routes/cron.mjs
  • scripts/mock-api/routes/integrations.mjs
  • scripts/mock-api/routes/invites.mjs
  • scripts/mock-api/routes/oauth.mjs
  • scripts/mock-api/routes/payments.mjs
  • scripts/mock-api/routes/user.mjs
  • scripts/mock-api/routes/version.mjs
  • scripts/mock-api/routes/webhooks.mjs
  • scripts/mock-api/server.mjs
  • scripts/mock-api/socket.mjs
  • scripts/mock-api/state.mjs

Comment thread app/src-tauri/src/core_process.rs Resolved
Comment thread app/test/e2e/helpers/core-rpc-node.ts Resolved
Comment thread scripts/mock-api/http.mjs Resolved
Comment thread scripts/mock-api/routes/invites.mjs Resolved
Comment thread scripts/mock-api/routes/payments.mjs Resolved
senamakel added 2 commits May 12, 2026 04:43
Three fixes from the first CI run:

* `pnpm/action-setup@v4` rejected both an explicit `version: 10` AND the
  `packageManager` field in package.json (ERR_PNPM_BAD_PM_VERSION).
  Removed `version:` from the macOS and Windows steps — the action now
  reads the version exclusively from `packageManager`.

* The Linux job tried to drive the .deb binary with tauri-driver, which
  speaks WebKitWebDriver / webkit2gtk and cannot drive the CEF-backed
  WebView (session timed out on POST /session). That's the same
  incompatibility the project documents in test.yml's commented-out
  block. Stripped the spec-run step — the Linux job now builds the
  debug binary only, so a Linux-breaking dep / config / Rust change
  still fails the PR but we don't pretend to drive specs we can't.
  Renamed to `E2E (Linux build only)` so the surface is honest.

* No change needed for macOS Mac2 step content yet — its setup
  failure was upstream of the actual driver.
`uname` on Windows GitHub runners (git-bash) returns MINGW64_NT-* /
MSYS_NT-* / Windows_NT, which fell through to the script's macOS else
branch and tried `--bundles app` — that's the macOS .app bundle and
errors on Windows. wdio.conf launches the bare .exe at
src-tauri/target/debug/OpenHuman.exe via tauri-driver, so `--no-bundle`
is what we want there (same as Linux).

Replaced the binary if/else with an explicit case so any future OS
mismatch fails fast with a clear error instead of silently picking
the wrong bundle target.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
.github/workflows/e2e.yml (1)

217-217: ⚡ Quick win

Add --locked to cargo install for reproducible CI builds.

cargo install tauri-driver --version 2.0.5 --locked will use the crate's packaged Cargo.lock and prevent transitive dependency drift during CI runs. Since tauri-driver 2.0.5 includes a Cargo.lock file, this flag is safe to use and improves reproducibility.

Suggested change
-        run: cargo install tauri-driver --version 2.0.5
+        run: cargo install tauri-driver --version 2.0.5 --locked
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/e2e.yml at line 217, Update the CI step that runs the
cargo install for tauri-driver by adding the --locked flag to the existing
command; specifically modify the run command string "cargo install tauri-driver
--version 2.0.5" to include "--locked" so it becomes "cargo install tauri-driver
--version 2.0.5 --locked" in the e2e workflow run step that installs
tauri-driver.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/e2e.yml:
- Around line 151-155: The workflow step "Install Appium and mac2 driver"
currently installs unpinned moving targets; define APPIUM_VERSION and
APPIUM_MAC2_VERSION environment variables and use them when installing to
guarantee compatibility (e.g. npm install -g appium@${APPIUM_VERSION} and appium
driver install mac2@${APPIUM_MAC2_VERSION}). Ensure the chosen
APPIUM_MAC2_VERSION is from the 1.x line if you are targeting Appium 2, or pick
compatible 2.x+ versions if you upgrade to Appium 3, and update the step that
runs "npm install -g appium" and "appium driver install mac2" to reference these
variables.
- Around line 163-172: Add an explicit id to the mega-flow step (e.g., id:
mega-flow) since it currently uses continue-on-error: true, and update the
artifact upload step's condition to also check that step's outcome (e.g., change
the if to include || steps.mega-flow.outcome == 'failure') so failures from the
mega-flow step will trigger Upload e2e artifacts on failure even when
continue-on-error is set.

---

Nitpick comments:
In @.github/workflows/e2e.yml:
- Line 217: Update the CI step that runs the cargo install for tauri-driver by
adding the --locked flag to the existing command; specifically modify the run
command string "cargo install tauri-driver --version 2.0.5" to include
"--locked" so it becomes "cargo install tauri-driver --version 2.0.5 --locked"
in the e2e workflow run step that installs tauri-driver.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 05a22e83-9279-4daf-8e8a-7724d83f99aa

📥 Commits

Reviewing files that changed from the base of the PR and between ba1360f and c692593.

📒 Files selected for processing (1)
  • .github/workflows/e2e.yml

Comment thread .github/workflows/e2e.yml Resolved
Comment thread .github/workflows/e2e.yml Resolved
Five small correctness/security fixes from CodeRabbit's first pass:

* app/src-tauri/src/core_process.rs — write the debug-only e2e token
  file with mode 0600 on Unix and sync_all before close. Default umask
  could leave the bearer credential world-readable on shared dev hosts.

* app/test/e2e/helpers/core-rpc-node.ts — strip the Authorization
  header from the port-probe path so a non-core HTTP service that
  happens to be bound to one of the candidate ports (7788–7793) doesn't
  receive our bearer as a side effect of discovery. 401 is now treated
  as a positive port match (endpoint exists, auth required) so the
  real call retries with auth attached.

* scripts/mock-api/http.mjs — reject the readBody promise on stream
  error / aborted so a wedged request can't hang the dispatcher.

* scripts/mock-api/routes/invites.mjs — tighten /invite/status to
  ^/invite/status(?:/[^/?]+)?/?(?:\?.*)?$ so it doesn't swallow
  unrelated /invite/status* paths and hide missing mocks.

* scripts/mock-api/routes/payments.mjs — preserve explicit 0 in
  POST /payments/credits/top-up. The previous `n || 10` coerced a
  legitimate 0 into the default; use Number.isFinite + range check
  so non-numeric bodies still fall back but 0 stays 0.
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 12, 2026
The script previously only had Linux and macOS branches:
  - Linux         → tauri-driver
  - else (macOS)  → Appium Mac2 (sourced e2e-resolve-node-appium.sh)

On Windows runners `uname` returns MINGW64_NT-* / MSYS_NT-* / Windows_NT
which fell into the macOS else and failed with
"ERROR: appium not found. Install with: npm install -g appium".

Replaced the if/else with a case that:
  - Linux + Windows/MINGW/MSYS/CYGWIN → start tauri-driver
    (tauri-driver.exe on Windows, picked up from %USERPROFILE%\.cargo\bin),
    log to $TMP on Windows, /tmp on Linux.
  - Darwin → Appium Mac2 (unchanged).
  - anything else → fail fast with a clear message.

Same approach as the e2e-build.sh case-style branching added in
47361e1. Windows e2e smoke (which fails fast on the WebView driver
incompatibility today) is still gated by `continue-on-error: true`
in the workflow so it doesn't block the PR.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/scripts/e2e-run-spec.sh`:
- Around line 144-149: The fallback for resolving TAURI_DRIVER_BIN can end up
using a Windows-style USERPROFILE path that fails POSIX -x checks; update the
logic around TAURI_DRIVER_BIN and TAURI_DRIVER_NAME so you try the POSIX
$HOME/.cargo/bin path first, and only if that isn't executable fall back to
USERPROFILE (or converted path) as a secondary option; change the branch that
currently sets
TAURI_DRIVER_BIN="${USERPROFILE:-$HOME}/.cargo/bin/$TAURI_DRIVER_NAME" to prefer
HOME (e.g., set TAURI_DRIVER_BIN="${HOME}/.cargo/bin/$TAURI_DRIVER_NAME" then
check -x and only then try
"${USERPROFILE:-$HOME}/.cargo/bin/$TAURI_DRIVER_NAME"), keeping the same -x
checks afterward.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ddfbe5cc-67ed-4690-8e6f-5895f1daf965

📥 Commits

Reviewing files that changed from the base of the PR and between 65679ec and ee03f0b.

📒 Files selected for processing (1)
  • app/scripts/e2e-run-spec.sh

Comment thread app/scripts/e2e-run-spec.sh Resolved
CodeRabbit caught that the Windows fallback
TAURI_DRIVER_BIN="${USERPROFILE:-$HOME}/.cargo/bin/$TAURI_DRIVER_NAME"
would expand to a Windows-style backslash path that bash's `-x` test
can't evaluate, so the script would falsely conclude the binary
"doesn't exist" even when it's installed.

Prefer $HOME (POSIX-friendly under git-bash) first. Only fall back to
$USERPROFILE if $HOME doesn't have the binary, converting via cygpath
when available so the result is still a POSIX path bash can stat.
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 12, 2026
@senamakel
senamakel marked this pull request as draft May 13, 2026 02:36
@senamakel
senamakel marked this pull request as ready for review May 13, 2026 02:44
senamakel added 2 commits May 12, 2026 20:10
Windows runs hit ECONNREFUSED on port 4723 because the config only
branched Linux vs default-to-Mac2:
  - Capabilities: Windows fell through to the macOS Mac2 block and got
    `platformName: mac` + Appium app caps, which Mac2 doesn't accept
    and which wouldn't match a tauri-driver session anyway.
  - Port: `isLinuxDriver ? 4444 : 4723` sent Windows to Appium's 4723
    instead of tauri-driver's 4444.

Group Windows with Linux as a tauri-driver host:
  - Capabilities → `[{ 'tauri:options': { application: getAppPath() } }]`
    (the existing `getAppPath()` win32 branch already returns
    `src-tauri/target/debug/OpenHuman.exe`).
  - Driver port → 4444 (TAURI_DRIVER_PORT honoured as before).
  - connectionRetry* → use the more generous Linux/CEF values since
    Windows cold session creation has the same shape.

Renamed `isLinuxDriver` to `isTauriDriverHost` so the gate name matches
what it actually means now.
CI Prettier flagged the multi-line `const isTauriDriverHost = ...`
declaration — the joined `process.platform === 'linux' || process.platform === 'win32'`
expression is 78 chars, well under the 100-col print width, so Prettier
collapses it to a single line. No behavior change.
@senamakel senamakel self-assigned this May 13, 2026
senamakel added 3 commits May 12, 2026 20:48
The Windows tauri-driver session creation failed with
`session not created: Microsoft Edge failed to start: crashed.`

Root cause: on Windows, tauri-driver delegates to MSEdgeDriver to
drive WebView2 — but OpenHuman's runtime is CEF (Chromium Embedded
Framework), not WebView2. msedgedriver tries to launch Edge to attach
to a WebView2 host that doesn't exist, and crashes. Same architectural
incompatibility as Linux's webkit2gtk-driver ↔ CEF.

Drop the smoke-spec run step (and the now-unused `cargo install
tauri-driver`); keep the build step so Windows-breaking dep/config/Rust
changes still fail the PR. Renamed to "E2E (Windows build only)" so
the surface is honest, matching the existing Linux build-only leg.
Windows build kept failing with
  error[E0061]: sys.refresh_processes(...) takes 2 args but 1 was supplied
  --> src/openhuman/local_ai/install.rs:26:9

but neither `refresh_processes` nor `sysinfo` appears anywhere in
src/openhuman/local_ai/install.rs on this branch (or in main). The
file at line 26 is `String::from_utf8_lossy(&output.stderr),`.

Diagnosis: Swatinem/rust-cache@v2 restored a target/ from an earlier
state where `local_ai/install.rs` *did* call refresh_processes, and
cargo cross-referenced that stale .rmeta during the fresh compile,
producing a diagnostic that points at the new line text but with the
old call's signature mismatch.

Bumped the cache key to `e2e-windows-v2` so this run starts cold and
the cache repopulates from the actual current sources.
senamakel added 2 commits May 12, 2026 22:57
…s (Windows build)

sysinfo 0.33 changed the signature of refresh_processes to require a second
bool arg (remove_dead_processes). The missing arg caused a compile error on
the Windows e2e leg in GitHub Actions. Pass false to preserve the previous
behaviour (dead-process entries are not pruned between calls).
# Conflicts:
#	src/openhuman/local_ai/install.rs
@senamakel
senamakel merged commit 9694dbe into tinyhumansai:main May 13, 2026
19 of 20 checks passed
AusAgentSmith pushed a commit to AusAgentSmith/openhuman that referenced this pull request May 23, 2026
senamakel added a commit to nocstah/openhuman that referenced this pull request Sep 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant