Conversation
🔐 Codex Security Review
Review SummaryOverall Risk: HIGH Findings[HIGH] Site-scoped URLs are enabled for pages that still use org-wide data/actions
NotesNo SQL injection, command injection, protobuf wire-format, plugin, infrastructure, Rust, or cryptostealing/pool-hijack issues were visible in this frontend-focused diff. Generated by Codex Security Review | |
There was a problem hiding this comment.
Pull request overview
This PR introduces path-based “site scope” routing for ProtoFleet by mounting Fleet under both /fleet/... (all-sites scope) and /:siteScope/fleet/... (single-site or unassigned scope), and makes the URL the source of truth for the active scope while keeping ?site= as a list-level filter that composes with the path scope.
Changes:
- Added site-scope routing helpers + a route-scope provider/layout to parse/prefix/unprefix Fleet paths.
- Updated Fleet navigation (primary nav + tabs/saved views) to preserve the current site scope in generated links.
- Updated Fleet list pages to apply scope ∩ filter semantics between the path scope and
?site=.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| client/src/protoFleet/routing/siteScope.tsx | Adds scope parsing and scoped/unscoped path helpers plus scope-providing layouts. |
| client/src/protoFleet/routing/siteScope.test.ts | Adds unit tests for scope parsing and path prefix/strip behavior. |
| client/src/protoFleet/router.tsx | Dual-mounts Fleet routes under unscoped /fleet and scoped /:siteScope/fleet. |
| client/src/protoFleet/features/fleetManagement/pages/RacksPage.tsx | Applies path-scope ∩ ?site= list-filter semantics for racks requests. |
| client/src/protoFleet/features/fleetManagement/pages/FleetBuildingsPage.tsx | Applies path-scope ∩ ?site= list-filter semantics for buildings requests. |
| client/src/protoFleet/features/fleetManagement/components/FleetViewTabs/FleetViewTabs.tsx | Ensures saved-view navigation preserves the active site scope. |
| client/src/protoFleet/features/fleetManagement/components/FleetLayout/FleetLayout.tsx | Makes Fleet tab routing scope-aware (including redirects / tab selection). |
| client/src/protoFleet/features/fleetManagement/components/Fleet/Fleet.tsx | Applies scope ∩ filter composition for miner list + total count queries. |
| client/src/protoFleet/config/navItems.ts | Marks Fleet primary nav item as “scopable”. |
| client/src/protoFleet/components/PageHeader/SitePicker/useActiveSite.ts | Makes useActiveSite() prefer route scope and mirror it into the persisted store. |
| client/src/protoFleet/components/PageHeader/SitePicker/useActiveSite.test.ts | Tests route-scope source-of-truth behavior and store mirroring. |
| client/src/protoFleet/components/PageHeader/SitePicker/SitePicker.tsx | Makes picker selections navigate to the equivalent scoped Fleet URL. |
| client/src/protoFleet/components/PageHeader/SitePicker/SitePicker.test.tsx | Tests picker-triggered navigation preserves the current Fleet path. |
| client/src/protoFleet/components/PageHeader/SitePicker/siteFilter.ts | Adds intersectSiteFilters() to implement scope ∩ filter semantics. |
| client/src/protoFleet/components/PageHeader/SitePicker/siteFilter.test.ts | Adds tests for filter composition behavior (including match-nothing sentinel). |
| client/src/protoFleet/components/PageHeader/SitePicker/index.ts | Exposes intersectSiteFilters from the SitePicker module barrel. |
| client/src/protoFleet/components/NavigationMenu/Navigation.tsx | Prefixes scopable nav links with the active scope and fixes active-item detection for scoped Fleet paths. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3818968bf9
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5596a22e47
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
🤖 Security review triage: the latest Codex Security Review on 26858dd has one remaining MEDIUM finding about scoped Dashboard/Groups/Energy/Activity URLs still rendering org-wide data. That is intentionally staged route plumbing per product direction for this PR; the site picker remains feature-flagged off until those pages receive end-to-end data scoping in follow-up work. The actionable filter-sentinel issue from the earlier review was fixed by replacing the invalid |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 26858dd9e2
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d44a7cc99a
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f938c87b7d
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
85d0aa4 to
a3a6036
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a3a60364c0
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d657ae9bf1
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 718481bb46
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
abf0c49 to
e6348a5
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e6348a53c0
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: edaf501a18
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
b076001 to
bcdd13f
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bcdd13f02d
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 40b6ce593a
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const createScopableRoutes = (absolute: boolean) => [ | ||
| ...(absolute ? [] : [{ index: true, element: <Navigate to="dashboard" replace /> }]), | ||
| createRoute(absolute ? "/dashboard" : "dashboard", <Dashboard />, { bg: "surface-5" }), | ||
| createFleetRoute(absolute ? "/fleet" : "fleet"), |
There was a problem hiding this comment.
Preserve selected site when leaving mismatched site details
Because this mounts bare /fleet as the explicit all-sites Fleet route, the existing mismatch guard in SiteDetailPage (navigate("/fleet")) no longer carries the selected site. If an operator with stored/selected site 8 opens /sites/7, that guard sends them to /fleet, this all-sites route lets useActiveSite mirror {kind:"all"} into the store, and Fleet renders/redirects in all-sites scope instead of the selected site; route that bounce through the selected scope (for example via scopedPath) before treating bare /fleet as all-sites.
Useful? React with 👍 / 👎.
Reviewable diff: +588/-694 across 42 files (excludes generated, test, and story files).
Summary
This PR makes ProtoFleet site scope URL-addressable by mounting scopable app routes under both explicit all-sites paths like
/dashboardand site-prefixed paths like/:siteScope/dashboard. The root path/becomes an app-entry alias that consults the persisted SitePicker preference once and redirects to the preferred dashboard scope. Fleet list pages keep?site=as a list filter, so filtered all-sites links like/fleet/miners?site=7continue to work.How it works
The router defines scopable routes once and mounts them twice: unscoped at
/dashboard,/fleet,/groups,/energy, and/activity, and scoped under/:siteScope/.... A route scope provider resolves numeric site-id segments and the reservedunassignedsegment, while rejecting unknown prefixes back to/.useActiveSite()reads route scope when present, validates loaded site IDs, and mirrors valid route scope into the Zustand UI store. The SitePicker now navigates to the equivalent scoped path when the current page is scopable, or to the scoped Dashboard landing from non-scopable pages. Fleet tabs, saved-view navigation, group links, and building links use shared scope helpers so they preserve the active path prefix, while explicit?site=deep links remain all-sites filtered links.Fleet list requests compose path scope with the list-level
?site=filter as an intersection./fleet/miners?site=7means all-sites scope filtered to site 7;/8/fleet/miners?site=7intentionally resolves to an empty server filter.Diagrams
flowchart TD A["Browser URL"] --> B{"Scopable route?"} B -->|"/dashboard, /fleet, /groups, /energy, /activity"| C["Route scope: all sites"] B -->|"<site-id>/..."| D["Route scope: site id"] B -->|"/unassigned/..."| E["Route scope: unassigned"] C --> F["useActiveSite"] D --> F E --> F F --> G["SitePicker label and persisted preference"] F --> H["Fleet list request scope"] H --> I["Intersect with ?site= list filter"]Areas of the code involved
client/src/protoFleet/router.tsx/entry redirect and dual-mounts Dashboard, Fleet, Groups, Energy, and Activity under unscoped and/:siteScopeparentsclient/src/protoFleet/routing/siteScope.tsxPageHeader/SitePickeruseActiveSite()route-aware and makes picker selections navigateNavigationMenu,navItems.ts,FleetLayout,FleetViewTabsFleet.tsx,RacksPage.tsx,FleetBuildingsPage.tsx?site=filters using intersection semanticsredirectLoaders.ts,useDeviceSetListState.ts?site=filter is present, and short-circuits explicit empty site intersectionsKey technical decisions & trade-offs
?site=as a list filtermatchNoneflag for disjoint scope/filter intersectionsTesting & validation
npm run lintnpx tsc --noEmitnpm test -- SitePicker useActiveSite FleetLayout siteScope siteFilter NavigationMenu SecondaryNavigation SiteList BuildingList --runNot covered here: slug persistence, scoping Dashboard/Groups/Energy/Activity data fetching, and removing legacy
?site=filter behavior.Fixes #511