✨ Load voting content from S3 with minimal voter status (main) - #3165
✨ Load voting content from S3 with minimal voter status (main)#3165edulix wants to merge 7 commits into
Conversation
|
Warning Review limit reachedNext included review available in 24 minutes. View limit detailsLimit details: You’ve used the included review currently available. This review ran on the open-source allowance, not this organization's plan, because the pull request author doesn't have an assigned seat. Waiting won't change this — ask an organization admin to assign them a seat, or add seats in Billing if every seat is already assigned, then retry. Review configuration: ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (67)
Comment |
There was a problem hiding this comment.
🟡 Changes recommended
There are correctness and CI-blocking issues in the changed code (notably JWT base64url decoding in voterSessionScope and related TypeScript/lint problems) that should be fixed before approval.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR shifts the voting portal’s bootstrap flow to fetch election/event metadata and selected ballot styles from published S3 snapshots referenced by a minimal GetVoterStatus query, while keeping voter-eligibility checks and isolating cached downloads/state by authenticated session. It also adds Playwright-based capture/scale runners to exercise full Chromium voting journeys.
Changes:
- Add
GetVoterStatusquery +useVoterContexthook to load published election/event metadata and (optionally) a selected ballot style from S3, then seed Apollo cache/Redux state. - Add session-scoping utilities and a
clearVoterSessionstore reset path tied to auth scope changes. - Add Playwright capture/scale/status harnesses and TypeScript typecheck scripts for the new e2e tooling.
File summaries
| File | Description |
|---|---|
| packages/yarn.lock | Adds Playwright dependency resolution for new load/capture tooling. |
| packages/voting-portal/tsconfig.json | Adds explicit Node/Jest types and formatting updates. |
| packages/voting-portal/tsconfig.capture.json | New TS config for Playwright capture/scale scripts. |
| packages/voting-portal/test/load/status.spec.ts | New Playwright test to measure authenticated GetVoterStatus performance. |
| packages/voting-portal/test/load/scale.spec.ts | New Playwright shard runner for finite multi-voter Chromium journeys. |
| packages/voting-portal/test/load/flow.ts | Shared Playwright helpers for login and casting flow. |
| packages/voting-portal/test/load/capture.spec.ts | New diagnostic Playwright capture for a full login-to-cast journey (HAR + summaries). |
| packages/voting-portal/test/load/ballotTypes.ts | New TS types for captured/prepared cast payloads and voter-status references. |
| packages/voting-portal/src/utils/voterSessionScope.ts | New helper to derive a cache partition key from JWT claims. |
| packages/voting-portal/src/utils/voterSessionScope.test.ts | Unit tests validating scope stability/invalidation behavior. |
| packages/voting-portal/src/translations/tl.ts | Adds new localized strings for invalid login hint parameters. |
| packages/voting-portal/src/translations/nl.ts | Adds new localized strings for invalid login hint parameters. |
| packages/voting-portal/src/translations/gl.ts | Adds new localized strings for invalid login hint parameters. |
| packages/voting-portal/src/translations/fr.ts | Adds new localized strings for invalid login hint parameters. |
| packages/voting-portal/src/translations/eu.ts | Adds new localized strings for invalid login hint parameters. |
| packages/voting-portal/src/translations/es.ts | Adds new localized strings for invalid login hint parameters. |
| packages/voting-portal/src/translations/cat.ts | Adds new localized strings for invalid login hint parameters. |
| packages/voting-portal/src/store/store.ts | Adds clearVoterSession action and root reducer reset on session changes. |
| packages/voting-portal/src/store/store.test.ts | New test ensuring session-scope changes reset eligibility/participation state. |
| packages/voting-portal/src/store/electionEvents/electionEventsSlice.test.ts | Updates test data to include delegated voting policy in presentation. |
| packages/voting-portal/src/store/castVotes/castVotesSlice.ts | Adds parseCastVoteStatus to validate DB status strings. |
| packages/voting-portal/src/store/castVotes/castVotesSlice.test.ts | Adds tests for cast status parsing behavior. |
| packages/voting-portal/src/services/PublishedBallots.ts | New S3 publication JSON loader with client-scoped in-flight dedupe and validation. |
| packages/voting-portal/src/services/PublishedBallots.test.ts | Tests worker concurrency and per-client in-flight download dedupe/eviction. |
| packages/voting-portal/src/services/ApolloErrors.ts | New helper to classify Apollo 4 transport errors without ApolloError wrapper. |
| packages/voting-portal/src/services/ApolloErrors.test.ts | Unit tests for the Apollo transport error classifier. |
| packages/voting-portal/src/routes/PublishedBallot.tsx | New route wrapper to seed store from published snapshots and preserve choices on refresh. |
| packages/voting-portal/src/routes/PublishedBallot.test.tsx | Test to ensure published-style reload preserves voter choices. |
| packages/voting-portal/src/routes/ElectionSelectionScreen.tsx | Switches bootstrap to useVoterContext, adjusts revote/materials logic and polling. |
| packages/voting-portal/src/routes/ConfirmationScreen.tsx | Improves mutation typing and guards print action when tracker URL is missing; adds testids. |
| packages/voting-portal/src/routes/BallotLocator.tsx | Removes ballot-style bootstrap query side effects. |
| packages/voting-portal/src/queries/GetVoterStatus.ts | New minimal query returning publication URL refs + cast metadata. |
| packages/voting-portal/src/queries/GetElections.ts | Removes eml field from elections query selection. |
| packages/voting-portal/src/providers/SettingsContextProvider.tsx | Widens children type to React.ReactNode. |
| packages/voting-portal/src/providers/AuthContextProvider.tsx | Widens children type to React.ReactNode. |
| packages/voting-portal/src/providers/ApolloContextProvider.tsx | Adds session scoping + store reset on scope changes; stops Apollo client on cleanup. |
| packages/voting-portal/src/providers/ApolloContextProvider.test.tsx | Tests refresh vs scope-change vs logout behavior for session state clearing. |
| packages/voting-portal/src/index.tsx | Adds PublishedBallot route wrapper under election route. |
| packages/voting-portal/src/hooks/useVoterContext.ts | New hook to load minimal status, download publication snapshots, and seed Apollo cache. |
| packages/voting-portal/src/hooks/useVoterContext.test.tsx | Tests schema validity, request minimization, scoping, retries, and download safety. |
| packages/voting-portal/src/hooks/useUpdateTranslation.ts | Adapts translation overwrite call to handle optional presentation. |
| packages/voting-portal/src/gql/graphql.ts | Regenerates GraphQL types (adds new fields/ops including get_ballot_files_urls). |
| packages/voting-portal/src/gql/gql.ts | Regenerates typed-document mapping including new GetVoterStatus. |
| packages/voting-portal/src/mocks/uiCoreTestEntry.ts | Extends ui-core re-exports for tests (ElectionEventPresentation + candidatePresentation). |
| packages/voting-portal/playwright.scale.config.ts | New Playwright config for scale shard runs. |
| packages/voting-portal/playwright.capture.config.ts | New Playwright config for capture/status runs. |
| packages/voting-portal/package.json | Adds Playwright dev dependency and typecheck scripts. |
| packages/voting-portal/graphql.schema.json | Updates introspection schema (includes get_ballot_files_urls and other additions). |
| packages/ui-essentials/src/components/CustomAutocompleteArrayInput/CustomAutocompleteArrayInput.tsx | Exports props interface for external typing. |
| packages/ui-essentials/package.json | Adds build:types script for emitting declaration files. |
| packages/ui-core/package.json | Adds build:types script for emitting declaration files. |
| packages/results-portal/src/gql/graphql.ts | Regenerates GraphQL types (schema additions). |
| packages/results-portal/graphql.schema.json | Updates introspection schema. |
| packages/package.json | Formats nohoist list and adds voting-portal typecheck pipeline script. |
| packages/graphql.schema.json | Updates shared introspection schema. |
| packages/ballot-verifier/src/gql/graphql.ts | Regenerates GraphQL types (schema additions). |
| packages/ballot-verifier/graphql.schema.json | Updates introspection schema. |
| packages/admin-portal/src/types/keycloak.ts | Adds TENANT_DELETE permission enum entry. |
| packages/admin-portal/src/translations/tl.ts | Adds translation for tenant-delete permission label. |
| packages/admin-portal/src/translations/nl.ts | Adds translation for tenant-delete permission label. |
| packages/admin-portal/src/translations/gl.ts | Adds translation for tenant-delete permission label. |
| packages/admin-portal/src/translations/fr.ts | Adds translation for tenant-delete permission label. |
| packages/admin-portal/src/translations/eu.ts | Adds translation for tenant-delete permission label. |
| packages/admin-portal/src/translations/es.ts | Adds translation for tenant-delete permission label. |
| packages/admin-portal/src/translations/en.ts | Adds translation for tenant-delete permission label. |
| packages/admin-portal/src/translations/cat.ts | Adds translation for tenant-delete permission label. |
| packages/admin-portal/src/gql/graphql.ts | Regenerates GraphQL types (schema additions). |
| packages/admin-portal/graphql.schema.json | Updates introspection schema. |
Review details
- Files reviewed: 67/68 changed files
- Comments generated: 5
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| const hasBallotId = !!ballotId | ||
| const {data: dataBallotStyles} = useQuery<GetBallotStylesQuery>(GET_BALLOT_STYLES) | ||
| const {data: dataElections, loading: loadingElections} = useQuery<GetElectionsQuery>( | ||
| GET_ELECTIONS, | ||
| { |
| const payload = token.split(".")[1].replace(/-/g, "+").replace(/_/g, "/") | ||
| const claims = JSON.parse(atob(payload)) |
| default: | ||
| throw new Error("Unknown cast vote status") | ||
| } |
| const initial = store.getState() | ||
| store.dispatch(setElection({id: "election", presentation: {}} as any)) | ||
| store.dispatch( |
There was a problem hiding this comment.
🔵 Needs a closer look
There are confirmed correctness/robustness issues in newly added session-scoping and status parsing that should be addressed before merge.
Review details
Suppressed comments (3)
packages/voting-portal/src/utils/voterSessionScope.ts:20
- JWT payloads are base64url-encoded and commonly omit padding; calling atob() on an unpadded payload can throw in some environments. In that failure mode this function falls back to returning the whole token, which changes on routine refresh (exp) and will unnecessarily clear the voter session cache partition.
packages/voting-portal/src/store/castVotes/castVotesSlice.ts:23 - The thrown error omits the unexpected status value, which makes production debugging harder when the backend adds/changes statuses. Include the received value in the message.
packages/voting-portal/src/routes/ElectionSelectionScreen.tsx:321 - This effect no longer references ballotStyle, but it still appears in the dependency list; meanwhile election is referenced in the condition but not listed. Updating the dependency array avoids unnecessary re-runs and keeps dependencies aligned with the values used inside the effect.
- Files reviewed: 67/68 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🟡 Changes recommended
A confirmed JWT base64url decoding issue can cause session scoping to fall back to the raw token (leading to unnecessary scope churn and state clears), and a test leaks a mocked global.fetch across files.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (1)
packages/voting-portal/src/utils/voterSessionScope.ts:9
- JWT payloads are base64url-encoded and are often unpadded; calling atob() on an unpadded payload can throw and make this function fall back to returning the full token. That can cause the session scope to change on routine token refreshes (clearing cached state unexpectedly) and also keeps the raw token string as the cache key.
- Files reviewed: 67/68 changed files
- Comments generated: 1
- Review effort level: Lite
| import {ApolloClient, InMemoryCache, ApolloLink} from "@apollo/client" | ||
| import {fetchPublicationJson, mapPublicationFiles, VoterFile} from "./PublishedBallots" | ||
|
|
There was a problem hiding this comment.
🔵 Needs a closer look
It introduces a new authentication-scoped bootstrap path (GraphQL + S3 publication hydration) that affects core voting flows and caching/state boundaries, warranting final human verification despite unit test coverage.
Review details
Suppressed comments (1)
packages/voting-portal/src/store/castVotes/castVotesSlice.ts:23
parseCastVoteStatusthrows a generic error that omits the unexpected status value, which makes production debugging harder when a new/invalid status reaches the client.
- Files reviewed: 67/68 changed files
- Comments generated: 0 new
- Review effort level: Lite
Parent issue: sequentech/meta#12767 One complete k6/Chromium guide covers setup, workload sizing, local/Docker/Kubernetes workers, reports and troubleshooting. Includes synchronized engine examples, CLI reference, a real report screenshot and a separate telephone guide. Validation: Docusaurus build, Markdown-transform tests and Chromium checks for synchronized tabs, persistence, keyboard navigation, mobile layout and report images. ### Stack 1. #3163 — documentation and code tabs 2. #3164 — publications and cast backend 3. #3165 — voting portal and browser adapters 4. #3149 — native Rust load tooling ### Documentation - **Voting load-testing guide** — [Docusaurus](https://docs.sequentech.io/docusaurus/pr-preview/pr-3163/docs/developers/voting-portal/voter-status-performance) · [GitHub](https://github.com/sequentech/step/blob/feat/meta-12767/main/docs/docusaurus/docs/07-developers/05-voting-portal/voter-status-performance.md) - **CLI setup** — [Docusaurus](https://docs.sequentech.io/docusaurus/pr-preview/pr-3163/docs/developers/cli/cli) · [GitHub](https://github.com/sequentech/step/blob/feat/meta-12767/main/docs/docusaurus/docs/07-developers/02-cli/01-cli_cli.md) - **Load CLI reference** — [Docusaurus](https://docs.sequentech.io/docusaurus/pr-preview/pr-3163/docs/developers/cli/voting-load-reference) · [GitHub](https://github.com/sequentech/step/blob/feat/meta-12767/main/docs/docusaurus/docs/07-developers/02-cli/voting-load-reference.md) - **Telephone load-testing guide** — [Docusaurus](https://docs.sequentech.io/docusaurus/pr-preview/pr-3163/docs/developers/ivr/telephone-load-testing-guide) · [GitHub](https://github.com/sequentech/step/blob/feat/meta-12767/main/docs/docusaurus/docs/07-developers/12-ivr/telephone-load-testing-guide.md) --------- Co-authored-by: Eduardo Robles <edulix@users.noreply.github.com>
Parent issue: https://github.com/sequentech/meta/issues/12767
Load election metadata and selected ballot styles from S3 using minimal GetVoterStatus. Isolate downloads by authenticated session, retain eligibility checks, and exercise full voting journeys through shared Chromium adapters.
Stack
Documentation