Skip to content

fix: surface awsUiAuth in /config so frontend Cognito login flow triggers#4610

Open
leonarduk wants to merge 9 commits into
mainfrom
fix/issue-4577-awsUiAuth-config
Open

fix: surface awsUiAuth in /config so frontend Cognito login flow triggers#4610
leonarduk wants to merge 9 commits into
mainfrom
fix/issue-4577-awsUiAuth-config

Conversation

@leonarduk

@leonarduk leonarduk commented Jun 22, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds AwsUiAuthConfig dataclass to backend/config.py, populated from new UI_AUTH_DOMAIN and UI_AUTH_CLIENT_ID env vars
  • serialise_config() in backend/routes/config.py now emits a camelCase awsUiAuth block when both env vars are set, giving the frontend the enabled, domain, and clientId fields it needs to start the Cognito PKCE login flow
  • backend/contracts_spa.py gets AwsUiAuthContract + an optional awsUiAuth field on ConfigContract
  • CDK: adds UiAuthDomain CfnParameter to BackendLambdaStack; passes UI_AUTH_DOMAIN and UI_AUTH_CLIENT_ID to the Lambda via add_environment() after the parameters are defined
  • Deploy workflow: reads UiAuthDomain from StaticSiteStack outputs and passes it as a --parameters argument to cdk deploy

Test plan

  • tests/test_config.py::test_aws_ui_auth_loads_from_envAwsUiAuthConfig populated from env vars
  • tests/test_config.py::test_aws_ui_auth_disabled_when_env_absent — defaults to enabled=False when env absent
  • tests/backend/routes/test_config.py::test_read_config_includes_aws_ui_auth_when_env_setawsUiAuth block present with correct camelCase keys
  • tests/backend/routes/test_config.py::test_read_config_omits_aws_ui_auth_when_disabledawsUiAuth absent when not configured
  • tests/backend/test_spa_response_contracts.pyConfigContract.model_validate still passes with optional awsUiAuth
  • All 44 related tests pass, no lint errors introduced

Closes #4577

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • The API /config endpoint now exposes AWS UI authentication as awsUiAuth (including domain and clientId) when enabled.
  • Security

    • Improved /timeseries/meta ticker/exchange validation to block XSS-style payloads, returning HTTP 400 for invalid formats.
  • Tests

    • Added and updated test coverage for AWS UI auth loading from environment variables and for rejecting malicious /timeseries/meta inputs.
    • Added assertions that awsUiAuth is omitted when not configured.

leonarduk and others added 6 commits June 19, 2026 23:29
#276

All three paths in `_resolve_ticker_exchange` now validate `sym` and `ex`
against `_TICKER_SEGMENT_RE` before returning, breaking the taint flow that
CodeQL's py/reflective-xss (CWE-079) analysis tracked from the `ticker`
query parameter to the response.  Removes the now-redundant `html.escape`
from the JSON response path (HTML-encoding inside JSON is incorrect for
non-HTML consumers and was only there as a CodeQL workaround).

Closes #4561

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…th dots

PR 4569's approach of applying _TICKER_SEGMENT_RE to resolver-returned values
breaks valid portfolio entries with dotted exchange codes (e.g. XLON.G) and
conflicts with three existing tests that document the intentional asymmetry:

- test_resolve_inferred_path_trusts_internal_data: asserts "XLON.G" passes
- test_timeseries_meta_html_xss_ticker_from_resolver_is_escaped: asserts
  resolver-returned XSS is HTML-escaped (not rejected with 400)
- test_timeseries_meta_html_xss_exchange_from_resolver_is_escaped: same

XSS defence for the resolver path is already provided by:
  - render_timeseries_html: html.escape(title) for the page heading
  - render_timeseries_html: df.to_html(escape=True) for table cells

Restore html.escape() in the JSON response path (removed by PR 4569) to
satisfy CodeQL's reflective-XSS check on this HTMLResponse-typed route.

User-supplied ticker/exchange (cases 1 and 2) retain strict _TICKER_SEGMENT_RE
validation; the new XSS-rejection tests in test_timeseries_meta_route.py all
pass because they test user-supplied inputs only.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… check

The three parametrised cases in test_timeseries_meta_xss_payload_rejected
all hit _TICKER_SEGMENT_RE validation before any data loading, so they can
only return 400, not 404.  Accepting 404 would let a response that echoes
the unescaped payload in an error body pass the test.

Add the content-type check to confirm the rejection is JSON (not HTML), so
the reflected input cannot be interpreted as markup by a browser.

Addresses DeepSeek review feedback (test assertion too permissive).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…lective-xss #276

Add _RESOLVER_OUTPUT_RE (^[A-Z0-9._\-]{1,100}$) applied to sym/ex returned
by _resolve_full_ticker.  This breaks the taint flow from the user-supplied
ticker query parameter to the HTML response that CodeQL tracked as alert #276.

The wider pattern permits dots so valid dotted exchange codes (e.g. XLON.G)
are accepted, while HTML-unsafe characters (<, >, &, ", ') are still rejected,
closing the XSS vector even if the resolver returns unexpected data.

Update test_timeseries_meta_html_xss_*_from_resolver_is_escaped → _is_rejected:
the defence is now Layer 1 (validation → 400) rather than Layer 2 (HTML escaping
→ 200 with entities).  test_resolve_inferred_path_trusts_internal_data docstring
updated to reflect _RESOLVER_OUTPUT_RE semantics.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…gers

The backend /config response was missing the awsUiAuth block, so the
frontend's ensureAwsUiAuth() call did nothing and every protected API
call went out without an Authorization header, causing 401s on /owners
and /groups.

Changes:
- backend/config.py: add AwsUiAuthConfig dataclass; load UI_AUTH_DOMAIN
  and UI_AUTH_CLIENT_ID env vars; include in Config.aws_ui_auth
- backend/contracts_spa.py: add AwsUiAuthContract; add optional
  awsUiAuth field (alias) to ConfigContract
- backend/routes/config.py: serialise_config transforms aws_ui_auth to
  camelCase awsUiAuth block; only emits it when enabled=True
- cdk/stacks/backend_lambda_stack.py: add UiAuthDomain CfnParameter;
  pass UI_AUTH_DOMAIN and UI_AUTH_CLIENT_ID to backend Lambda via
  add_environment() after params are defined
- .github/workflows/deploy-lambda.yml: read UiAuthDomain from
  StaticSiteStack outputs; pass as --parameters to cdk deploy

Closes #4577

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2395a994-70de-46a0-85c3-29ccdc5a3e82

📥 Commits

Reviewing files that changed from the base of the PR and between 728887e and f56709f.

📒 Files selected for processing (1)
  • tests/test_app.py

📝 Walkthrough

Walkthrough

The PR adds awsUiAuth (domain, clientId, enabled) to the backend /config response by introducing AwsUiAuthConfig/AwsUiAuthContract data shapes, reading UI_AUTH_DOMAIN and UI_AUTH_CLIENT_ID from Lambda environment variables, wiring those via a new CDK CfnParameter, and propagating them through the GitHub Actions deploy workflow. It also fixes a reflective XSS vector in timeseries_meta by validating resolver-returned ticker and exchange values and rejecting unsafe content with HTTP 400.

Changes

AWS UI Auth config propagation

Layer / File(s) Summary
AwsUiAuth data contracts
backend/config.py, backend/contracts_spa.py
Adds AwsUiAuthConfig dataclass and AwsUiAuthContract Pydantic model; extends Config and ConfigContract with aws_ui_auth/awsUiAuth fields; exports AwsUiAuthContract from module __all__.
Environment variable loading
backend/config.py
load_config() reads UI_AUTH_DOMAIN and UI_AUTH_CLIENT_ID, normalises empty values to None, enables authentication only when both variables are present, and constructs AwsUiAuthConfig for the Config instance.
Config route serialisation
backend/routes/config.py
Refactors imports to use config_module.config; extends serialise_config to extract aws_ui_auth and emit an awsUiAuth response object with enabled, domain, and clientId fields when authentication is enabled.
CDK and CI/CD infrastructure wiring
cdk/stacks/backend_lambda_stack.py, .github/workflows/deploy-lambda.yml
Adds UiAuthDomain CfnParameter to BackendLambdaStack and sets Lambda environment variables UI_AUTH_DOMAIN and UI_AUTH_CLIENT_ID; deploy workflow extracts UiAuthDomain from StaticSiteStack CloudFormation outputs and passes it to CDK deployment.
AwsUiAuth test coverage
tests/test_config.py, tests/backend/routes/test_config.py, cdk/tests/test_backend_lambda_stack.py
Adds tests for environment variable loading (enabled/disabled), verifies /config response output shape with correct field mapping and omission, extends CDK fixture to isolate UI_AUTH_DOMAIN during synthesis.

Timeseries meta endpoint XSS fix

Layer / File(s) Summary
Resolver output validation
backend/routes/timeseries_meta.py
Introduces _RESOLVER_OUTPUT_RE regex (permits dots, blocks XSS characters); applies validation to inferred sym/ex values and raises HTTP 400 on mismatch; removes comment treating resolver output as unconditionally trusted.
XSS rejection test coverage
tests/routes/test_timeseries_meta.py, tests/test_timeseries_meta_route.py
Renames and rewrites resolver XSS unit tests to expect HTTP 400 JSON instead of 200 escaped HTML; adds parametrised integration tests for XSS payload combinations; clarifies that dots remain permitted in resolver output per the allowlist regex.

Sequence Diagram

sequenceDiagram
  participant Client as Frontend Browser
  participant ConfigEndpoint as Backend /config
  participant Lambda as Backend Lambda
  participant EnvVars as Lambda Environment
  Client->>ConfigEndpoint: GET /config
  ConfigEndpoint->>Lambda: load_config()
  Lambda->>EnvVars: read UI_AUTH_DOMAIN<br/>read UI_AUTH_CLIENT_ID
  EnvVars-->>Lambda: domain, client_id values
  Lambda->>Lambda: construct AwsUiAuthConfig<br/>(enabled if both present)
  Lambda-->>ConfigEndpoint: Config with aws_ui_auth
  ConfigEndpoint->>ConfigEndpoint: serialise_config()<br/>convert aws_ui_auth to awsUiAuth
  ConfigEndpoint-->>Client: JSON with awsUiAuth block
  Client->>Client: ensureAwsUiAuth()<br/>redirect to Cognito if enabled
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Possibly related PRs

  • leonarduk/allotmint#4243: Adds Playwright smoke test exercising the Cognito hosted UI callback → /token/cognito exchange, complementing the awsUiAuth domain/clientId contract this PR establishes.
  • leonarduk/allotmint#4458: Implements React frontend code consuming the awsUiAuth domain/clientId from /config to render the AWS UI "Sign in" flow, directly using the backend response structure this PR introduces.
  • leonarduk/allotmint#4569: Concurrently modifies backend/routes/timeseries_meta.py to tighten allowlist/regex validation for resolver-inferred ticker/exchange values, overlapping the XSS rejection logic in this PR.

Poem

🐇 Hopping through the config trail,
Auth fields found—the missing grail!
awsUiAuth crowns /config reply,
domain and clientId shall not shy.
XSS villains face HTTP 400 with pride,
The bunny fixed the login flow worldwide! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.36% 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 summarises the primary change: exposing awsUiAuth configuration in the /config endpoint to enable the frontend Cognito login flow.
Linked Issues check ✅ Passed The PR fully satisfies all coding-related acceptance criteria from issue #4577: /config now exposes awsUiAuth with enabled/domain/clientId; backend config reads UI_AUTH_DOMAIN and UI_AUTH_CLIENT_ID env vars; SPA contracts serialise the data; CDK passes Cognito credentials as Lambda env vars; comprehensive test coverage validates the implementation.
Out of Scope Changes check ✅ Passed All changes are directly scoped to issue #4577: configuration model updates, SPA contract extensions, CDK environment variable wiring, deployment workflow updates, and defensive ticker/exchange validation on /timeseries/meta with supporting tests.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-4577-awsUiAuth-config
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch fix/issue-4577-awsUiAuth-config

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

@github-actions

Copy link
Copy Markdown

DeepSeek AI Code Review

1. Acceptance criteria

The diff satisfies all acceptance criteria from the linked issue:

  • /config response includes awsUiAuth with enabled, domain, clientId (via serialise_config in backend/routes/config.py lines 70-76)
  • ✅ CDK stack passes Cognito domain and client ID as Lambda environment variables (backend_lambda_stack.py lines 362-363)
  • backend/config.py model includes AwsUiAuthConfig (lines 88-92) and is wired into Config (line 171)
  • backend/contracts_spa.py serialises awsUiAuth fields (lines 14-17, 49)
  • ✅ Tests cover both enabled and disabled states (test_config.py lines 356-376, test_config.py lines 379-382)

The remaining AC items (redirect to Cognito, token storage, 200 responses) are frontend-side behaviours that depend on this backend fix — they're correctly scoped as downstream effects.

2. Bugs and logic errors

No blocking bugs found.

One minor observation: in backend/routes/config.py line 70, the check raw.get("enabled") will be False for the falsy-but-valid case where enabled is explicitly False. This is correct behaviour — you want to omit the block when auth is disabled. No issue.

3. API, data, and workflow safety

No blocking concerns.

  • The serialise_config function correctly pops aws_ui_auth from the raw dict and remaps to camelCase awsUiAuth — consistent with the frontend's expected contract.
  • The AwsUiAuthContract in contracts_spa.py uses Field(alias="clientId") which aligns with the camelCase serialisation.
  • The deploy workflow (deploy-lambda.yml lines 422-432) correctly fetches UiAuthDomain from StaticSiteStack outputs and passes it as a parameter. The fallback to empty string when missing is safe.
  • The timeseries_meta.py changes are unrelated to the auth fix but appear to be a separate security hardening (XSS prevention). They don't interact with the auth flow.

4. Test coverage

Adequate for the acceptance criteria.

  • test_config.py: Tests both the enabled case (env vars set → aws_ui_auth.enabled=True) and disabled case (env vars absent → enabled=False)
  • test_config.py (routes): Tests that /config response includes awsUiAuth with correct camelCase keys when enabled, and omits it when disabled
  • The CDK test (test_backend_lambda_stack.py) includes UI_AUTH_DOMAIN in the env vars to clear, ensuring deterministic template synthesis

Missing but non-blocking: No test verifies that the UI_AUTH_DOMAIN and UI_AUTH_CLIENT_ID env vars are actually passed through to the Lambda function's environment in the CDK template. A snapshot test or assertion on the synthesised template would catch regressions if someone refactors the env var wiring.

5. Suggested follow-up issues (non-blocking)

  • Add CDK template assertion test for UI_AUTH_DOMAIN and UI_AUTH_CLIENT_ID Lambda environment variables
  • Consider adding an integration test that deploys with UI_AUTH_DOMAIN set and verifies /config returns awsUiAuth

APPROVE


Reviewed by DeepSeek via deepseek-pr-review.yml. Advisory only.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
cdk/stacks/backend_lambda_stack.py (1)

348-368: 🧹 Nitpick | 🔵 Trivial | 🏗️ Heavy lift

Split BackendLambdaStack.__init__ before extending parameter wiring

The constructor is already significantly oversized; adding more deployment/config branches here makes stack behaviour harder to reason about and test. Please extract auth-parameter/env wiring into a dedicated helper.

As per coding guidelines, “Function length must be ~60 lines maximum; refactor before adding more to an oversized function.”

🤖 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 `@cdk/stacks/backend_lambda_stack.py` around lines 348 - 368, Extract the
auth-parameter and environment variable wiring logic from the
BackendLambdaStack.__init__ method into a dedicated helper method. Create a new
private method (e.g., _configure_auth_parameters or _setup_ui_auth) that
encapsulates the CfnParameter creation for ui_auth_domain_param and
ui_auth_client_id_param, along with the corresponding backend_fn.add_environment
calls for UI_AUTH_DOMAIN and UI_AUTH_CLIENT_ID. Call this new helper method from
__init__ to keep the constructor focused and maintainable.

Source: Coding guidelines

backend/config.py (1)

397-404: 🧹 Nitpick | 🔵 Trivial | 🏗️ Heavy lift

Refactor load_config before adding more env-mapping logic

This function is already far beyond the repository’s size limit; adding more config branches here increases maintenance risk. Please extract the UI auth env parsing into a helper and keep load_config as an orchestrator.

As per coding guidelines, “Function length must be ~60 lines maximum; refactor before adding more to an oversized function.”

🤖 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 `@backend/config.py` around lines 397 - 404, The load_config function exceeds
the recommended maximum function length and adding more configuration branches
increases maintenance risk. Extract the UI auth environment variable parsing
logic (the code that reads UI_AUTH_DOMAIN and UI_AUTH_CLIENT_ID and creates the
AwsUiAuthConfig object) into a separate helper function. Create a new helper
function that encapsulates this UI auth configuration parsing and returns the
AwsUiAuthConfig, then replace the inline logic in load_config with a call to
this helper function to keep load_config focused as an orchestrator.

Source: Coding guidelines

🤖 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.

Nitpick comments:
In `@backend/config.py`:
- Around line 397-404: The load_config function exceeds the recommended maximum
function length and adding more configuration branches increases maintenance
risk. Extract the UI auth environment variable parsing logic (the code that
reads UI_AUTH_DOMAIN and UI_AUTH_CLIENT_ID and creates the AwsUiAuthConfig
object) into a separate helper function. Create a new helper function that
encapsulates this UI auth configuration parsing and returns the AwsUiAuthConfig,
then replace the inline logic in load_config with a call to this helper function
to keep load_config focused as an orchestrator.

In `@cdk/stacks/backend_lambda_stack.py`:
- Around line 348-368: Extract the auth-parameter and environment variable
wiring logic from the BackendLambdaStack.__init__ method into a dedicated helper
method. Create a new private method (e.g., _configure_auth_parameters or
_setup_ui_auth) that encapsulates the CfnParameter creation for
ui_auth_domain_param and ui_auth_client_id_param, along with the corresponding
backend_fn.add_environment calls for UI_AUTH_DOMAIN and UI_AUTH_CLIENT_ID. Call
this new helper method from __init__ to keep the constructor focused and
maintainable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: cc78dbc0-f5df-4dbb-997c-18cd6984896f

📥 Commits

Reviewing files that changed from the base of the PR and between 3b802aa and 2da1b5f.

📒 Files selected for processing (11)
  • .github/workflows/deploy-lambda.yml
  • backend/config.py
  • backend/contracts_spa.py
  • backend/routes/config.py
  • backend/routes/timeseries_meta.py
  • cdk/stacks/backend_lambda_stack.py
  • cdk/tests/test_backend_lambda_stack.py
  • tests/backend/routes/test_config.py
  • tests/routes/test_timeseries_meta.py
  • tests/test_config.py
  • tests/test_timeseries_meta_route.py

@leonarduk leonarduk self-assigned this Jun 22, 2026
@github-actions

Copy link
Copy Markdown

DeepSeek AI Code Review

1. Acceptance criteria

The diff satisfies all acceptance criteria:

  • /config response includes awsUiAuth with enabled, domain, clientId — implemented in serialise_config() (routes/config.py:70-76) and AwsUiAuthContract (contracts_spa.py:14-17)
  • ✅ CDK stack passes Cognito domain and client ID as Lambda env vars — backend_fn.add_environment("UI_AUTH_DOMAIN", ...) and UI_AUTH_CLIENT_ID (backend_lambda_stack.py:367-368)
  • backend/config.py model includes aws_ui_auth fields — AwsUiAuthConfig dataclass (config.py:88-91) and field in Config (config.py:171)
  • backend/contracts_spa.py serialises fields — AwsUiAuthContract and ConfigContract.aws_ui_auth (contracts_spa.py:49)
  • ✅ Tests cover both enabled and disabled states — test_read_config_includes_aws_ui_auth_when_env_set and test_read_config_omits_aws_ui_auth_when_disabled (test_config.py:95-127)
  • ✅ CI workflow passes UiAuthDomain parameter — deploy-lambda.yml:449-456

2. Bugs and logic errors

No blocking bugs found. The logic is sound:

  • enabled is derived from the conjunction of both env vars being present (config.py:399), preventing partial configuration
  • The serialise_config() function correctly renames client_id to clientId for camelCase frontend contract (routes/config.py:74)
  • The awsUiAuth key is omitted entirely when disabled (routes/config.py:71), matching frontend's ensureAwsUiAuth() expectation

3. API, data, and workflow safety

No blocking concerns. Key safety points:

  • The UiAuthDomain CfnParameter has an empty default (backend_lambda_stack.py:354), so existing stacks without the parameter won't break — they'll just get empty env vars, which correctly disables awsUiAuth
  • The deploy workflow gracefully handles missing UiAuthDomain output (deploy-lambda.yml:425-428), defaulting to empty string
  • The _auth_env_vars tuple in the CDK test was updated to include UI_AUTH_DOMAIN (test_backend_lambda_stack.py:33), preventing test pollution from local env

4. Test coverage

Adequate coverage for the acceptance criteria. The three new tests cover:

  1. test_read_config_includes_aws_ui_auth_when_env_set — verifies full contract shape including camelCase keys
  2. test_read_config_omits_aws_ui_auth_when_disabled — verifies key is absent when not configured
  3. test_aws_ui_auth_loads_from_env / test_aws_ui_auth_disabled_when_env_absent — verifies config model loading from env vars

One minor gap: there's no integration test verifying that the CDK parameter wiring actually produces the correct env vars in the Lambda function. However, this is acceptable given the CDK test validates the template structure and the backend tests validate the runtime behavior.

5. Suggested follow-up issues (non-blocking)

  • Consider adding an end-to-end smoke test that verifies /config returns awsUiAuth after a deployment with Cognito configured
  • The serialise_config() function could benefit from a type hint on the return value for better IDE support

APPROVE


Reviewed by DeepSeek via deepseek-pr-review.yml. Advisory only.

…dRouter

Starlette 1.x (lambda-compat job, backend/requirements.txt) returns
_IncludedRouter objects in app.routes alongside Route objects; these
lack a .path attribute and caused AttributeError on the set comprehension.
Filter with isinstance(route, APIRoute) — the same pattern used in
tests/backend/test_smoke_endpoint_list.py — so the test is robust
across both 0.49.x and 1.x starlette versions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

DeepSeek AI Code Review

1. Acceptance criteria

The diff satisfies all acceptance criteria:

  • /config response includes awsUiAuth with enabled, domain, clientId (lines in routes/config.py serialization, contracts_spa.py model)
  • ✅ CDK stack passes Cognito domain and client ID as Lambda environment variables (backend_lambda_stack.py lines 345-372)
  • backend/config.py model includes AwsUiAuthConfig with the required fields (lines 88-91)
  • backend/contracts_spa.py serializes awsUiAuth into the SPA response (line 49)
  • ✅ Tests cover both enabled and disabled states (test_config.py lines 356-378, test_config.py lines 381-384)

The remaining AC items (redirect behavior, token storage, 200 responses) are frontend-side behaviors that depend on this backend fix — they cannot be verified from this diff alone but are correctly enabled by it.

2. Bugs and logic errors

No blocking issues found. The logic is sound:

  • AwsUiAuthConfig.enabled is correctly derived from the presence of both env vars (line 397-399 in config.py)
  • The serialization in routes/config.py correctly transforms snake_case to camelCase (client_idclientId, line 76)
  • The awsUiAuth key is omitted entirely when disabled (line 72 checks raw.get("enabled")), matching frontend expectations
  • The CDK parameter defaults to empty string when context/env is absent, gracefully disabling the feature

3. API, data, and workflow safety

No blocking issues found. Key safety considerations are handled:

  • Backward compatibility: When UI_AUTH_DOMAIN/UI_AUTH_CLIENT_ID are absent (existing deployments), awsUiAuth is omitted from /config — no regression for environments that don't use Cognito
  • CI/CD safety: The deploy workflow gracefully handles missing UiAuthDomain output (line 427-430 in deploy-lambda.yml), defaulting to empty string
  • Test isolation: The CDK test explicitly removes UI_AUTH_DOMAIN from env (line 33 in test_backend_lambda_stack.py) to keep template deterministic
  • No secrets exposed: Only the Cognito domain (public URL) and client ID (non-secret) are passed — no client secret is involved

4. Test coverage

Adequate coverage for the acceptance criteria:

  • test_read_config_includes_aws_ui_auth_when_env_set — verifies full serialization with camelCase keys
  • test_read_config_omits_aws_ui_auth_when_disabled — verifies omission when not configured
  • test_aws_ui_auth_loads_from_env — verifies config model loads from env vars
  • test_aws_ui_auth_disabled_when_env_absent — verifies disabled state

Missing but non-blocking: No integration test verifies the full end-to-end flow (CDK → Lambda env → /config response). This is acceptable as the unit tests cover each layer independently.

5. Suggested follow-up issues (optional)

  • Consider adding an integration test that deploys a test stack and verifies /config response shape

  • The timeseries_meta.py changes (XSS hardening) appear unrelated to the auth fix — consider splitting into a separate PR for cleaner history

  • APPROVE


Reviewed by DeepSeek via deepseek-pr-review.yml. Advisory only.

In Starlette 1.x (backend/requirements.txt) include_router wraps routes
in _IncludedRouter objects; filtering with isinstance(route, APIRoute)
silently excludes them and causes the rebalance route to be missed.

Switch to posting to /rebalance via TestClient and asserting the response
is not 404 — this is robust across all Starlette versions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.

Bug: /owners and /groups return HTTP 401 — awsUiAuth config missing from /config, Cognito login flow never triggered

1 participant