test(integration): bypass SSO browser UI with direct OIDC API login flow#2980
test(integration): bypass SSO browser UI with direct OIDC API login flow#2980
Conversation
WalkthroughThis pull request refactors the login authentication flow to support API-based OIDC login alongside UI-driven approaches. Changes include extracting OIDC token acquisition into a reusable 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
This PR has been deployed to https://linagora.github.io/twake-on-matrix/2980 |
3b76faa to
93d1198
Compare
e13ab5e to
66f3f41
Compare
Replace the browser-based SSO login in integration tests with a headless HTTP OIDC flow. The old approach was brittle: it depended on the device locale (button labels), required navigating the LemonLDAP browser modal, and was hard to debug when the SSO portal changed its response structure. Key changes: - Extract getLoginTokenViaOIDC() in CoreRobot: runs all 7 OIDC steps (including lemonldappdata cookie forwarding and consent-page fallback) via raw HTTP, returning a one-time loginToken without any UI interaction. - Add loginViaApi() in LoginRobot: calls the OIDC helper then feeds the loginToken directly to the app via the /onAuthRedirect deep link using TwakeApp.router.go(), bypassing the app_links listener. - Simplify LoginScenario.login() to a single loginViaApi() call. - Add patrol_cli dev dependency for running Patrol tests from CLI. - Add .mcp.json MCP servers configuration.
On cold start via SSO deep link, AppConfig.homeserver may be empty when OnAuthRedirect mounts. Reading it before await initConfigCompleter.future caused a silent auth failure. homeserverFromRoute is now String? — only the route param (available synchronously) is captured before the await. The fallback to AppConfig.homeserver is deferred to after initConfig resolves, where it is guaranteed to be populated. Also fix InitConfigMixin to ensure initConfigCompleter is always completed even when the config fetch throws, and add mounted guards to prevent use-after-dispose crashes.
66f3f41 to
afac130
Compare
There was a problem hiding this comment.
Gates Passed
3 Quality Gates Passed
See analysis details in CodeScene
Quality Gate Profile: The Bare Minimum
Install CodeScene MCP: safeguard and uplift AI-generated code. Catch issues early with our IDE extension and CLI tool.
|
@coderabbitai review please |
|
🧠 Learnings used✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
lib/presentation/mixins/init_config_mixin.dart (1)
35-43:⚠️ Potential issue | 🟠 MajorComplete
initConfigCompleterwith the real success state.The catch path still completes the mobile config future with
true.OnAuthRedirect.tryLoggingUsingToken()now uses that boolean to decide whether config is usable, so aloadEnvironment()failure will be cached as a successful init and the flow will continue with unset config.Suggested fix
Future<void> initConfigMobile() async { + var isConfigured = true; try { AppConfig.loadEnvironment(); } catch (e) { + isConfigured = false; Logs().e('[ConfigLoader] Config mobile error', e); } if (!AppConfig.initConfigCompleter.isCompleted) { - AppConfig.initConfigCompleter.complete(true); + AppConfig.initConfigCompleter.complete(isConfigured); } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/presentation/mixins/init_config_mixin.dart` around lines 35 - 43, In initConfigMobile, the catch block currently still completes AppConfig.initConfigCompleter with true causing failures to be treated as success; change the logic so AppConfig.initConfigCompleter.complete is called with true only on successful AppConfig.loadEnvironment() and complete(false) in the catch path (or completeError) so callers like OnAuthRedirect.tryLoggingUsingToken() receive the real success state; update references in this function (initConfigMobile), the load call (AppConfig.loadEnvironment), the completer usage (AppConfig.initConfigCompleter.complete) and the error log (Logs().e) accordingly.
🧹 Nitpick comments (1)
.mcp.json (1)
3-6: Consider pinningchrome-devtools-mcpto a specific version.Using
@latesttag can lead to unexpected behavior if the package releases breaking changes. For development tooling stability, consider pinning to a specific version (e.g.,chrome-devtools-mcp@1.2.3).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.mcp.json around lines 3 - 6, Update the chrome-devtools mcp invocation to pin the package to a specific released version instead of using the `@latest` tag: replace the "chrome-devtools-mcp@latest" entry inside the args array for the "chrome-devtools" command (the npx invocation) with a concrete semver string like "chrome-devtools-mcp@1.2.3" (pick the current tested release), and document or add a comment noting to bump this version intentionally when upgrading.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.mcp.json:
- Around line 17-24: Create the missing executable script at .claude/run-patrol
which wraps the actual patrol startup command (e.g., invokes the test runner or
server used in this repo) and respects the PROJECT_ROOT and PATROL_FLAGS env
vars; ensure the script is added to the repo, marked executable, and contains
robust error handling and logging so failures surface. Replace the literal
placeholder "<YOUR_DEVICE_ID>" in the PATROL_FLAGS value with either a real
device identifier or a shell-friendly substitution (e.g., read from an
environment variable like $DEVICE_ID) so the command in .mcp.json becomes usable
at runtime, and verify the .claude/run-patrol script reads and uses PATROL_FLAGS
when launching the patrol process.
In `@integration_test/base/core_robot.dart`:
- Around line 208-215: getLoginTokenViaOIDC currently reads
MATRIX_URL/SSO_URL/CHAT_URL from environment while loginViaApi now accepts a
serverUrl, which can cause mismatched homeservers; update getLoginTokenViaOIDC
to accept a serverUrl (String serverUrl) and use it to derive or override
matrix/sso/chat URLs instead of String.fromEnvironment, and update all callers
to forward the selected serverUrl (or alternatively remove serverUrl from
loginViaApi if you prefer the env-only contract). Specifically, change the
getLoginTokenViaOIDC signature and references inside the function (use the
passed serverUrl when constructing endpoints for the OIDC flow), then update
call sites that invoke getLoginTokenViaOIDC to pass the same serverUrl used for
loginViaApi so both flows target the same homeserver.
- Around line 404-407: The substring calls pass responseBody.length.clamp(0,
300) (a num) to String.substring which requires an int; fix both occurrences by
converting the clamp result to an int (e.g., call .toInt() after clamp) or use
an int-aware alternative like min(responseBody.length, 300). Update the
substring invocations that use responseBody.length.clamp(...) so they provide an
int end index (e.g., responseBody.length.clamp(0,300).toInt() or
math.min(responseBody.length,300)).
In `@lib/pages/login/on_auth_redirect.dart`:
- Around line 90-96: OnAuthRedirect currently reads AppConfig.homeserver on web
before awaiting AppConfig.initConfigCompleter.future, which can snapshot an
empty/stale homeserver; modify the web branch so it does not read
AppConfig.homeserver until after awaiting AppConfig.initConfigCompleter.future
(or otherwise defer using AppConfig.homeserver as a fallback) and update the
later logic that prefers the earlier snapshot (the same logic affecting the
other web-read block) to instead prefer the post-init value; locate uses in
OnAuthRedirect and references to AppConfig.initConfigCompleter and
AppConfig.homeserver to make this change.
---
Outside diff comments:
In `@lib/presentation/mixins/init_config_mixin.dart`:
- Around line 35-43: In initConfigMobile, the catch block currently still
completes AppConfig.initConfigCompleter with true causing failures to be treated
as success; change the logic so AppConfig.initConfigCompleter.complete is called
with true only on successful AppConfig.loadEnvironment() and complete(false) in
the catch path (or completeError) so callers like
OnAuthRedirect.tryLoggingUsingToken() receive the real success state; update
references in this function (initConfigMobile), the load call
(AppConfig.loadEnvironment), the completer usage
(AppConfig.initConfigCompleter.complete) and the error log (Logs().e)
accordingly.
---
Nitpick comments:
In @.mcp.json:
- Around line 3-6: Update the chrome-devtools mcp invocation to pin the package
to a specific released version instead of using the `@latest` tag: replace the
"chrome-devtools-mcp@latest" entry inside the args array for the
"chrome-devtools" command (the npx invocation) with a concrete semver string
like "chrome-devtools-mcp@1.2.3" (pick the current tested release), and document
or add a comment noting to bump this version intentionally when upgrading.
🪄 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: f1b0fac2-1a21-4333-9e97-8acceced2d59
⛔ Files ignored due to path filters (1)
pubspec.lockis excluded by!**/*.lock
📒 Files selected for processing (7)
.mcp.jsonintegration_test/base/core_robot.dartintegration_test/robots/login_robot.dartintegration_test/scenarios/login_scenario.dartlib/pages/login/on_auth_redirect.dartlib/presentation/mixins/init_config_mixin.dartpubspec.yaml
Problem
The integration test login was brittle:
Solution
Replace the browser-based SSO flow with a headless HTTP OIDC flow that runs entirely via
dart:ioHttpClient, then feeds the resultingloginTokendirectly to the app.Changes
core_robot.dart— ExtractgetLoginTokenViaOIDC(username, password): runs all 7 OIDC steps over HTTP includinglemonldappdatacookie forwarding and consent-page fallback. Returns(loginToken, lemonldap).login_robot.dart— AddloginViaApi(): calls the OIDC helper then navigates viaTwakeApp.router.go('/onAuthRedirect?loginToken=…&homeserver=…'), bypassingapp_linksentirely.login_scenario.dart— Reducelogin()to a singleloginViaApi()call; removes fragile UI steps.on_auth_redirect.dart— ReadGoRouterStateparams synchronously before anyawait(inherited widget anti-pattern fix), addmountedguards, supporthomeserveras query param.init_config_mixin.dart— EnsureinitConfigCompleteris always completed even on config fetch error.pubspec.yaml— Addpatrol_clidev dependency.Test example
Enregistrement.de.l.ecran.2026-04-02.a.09.16.16.mov
Summary by CodeRabbit
Bug Fixes
Tests