Software: fleet inventory page (All Software / Updates / Vulnerabilities) - #361
pavlo-flamingo wants to merge 8 commits into
Conversation
Adds /software, built from the Figma "All Software" design: one row per software title aggregated across the fleet, on Relay against the new softwares(...) connection. - Search, infinite scroll, server-side sort on DEVICES and VULNS. - Cells per the design: name + publisher, current version with the OUTDATED chip and the "+N older versions" line, device count, severity tag with the CVE count or "no CPE match". - Two sibling tabs share the table with a fixed scope: /software/updates (versionStatuses: OUTDATED) and /software/vulnerabilities (minSeverity: LOW). - Sidebar entry between Monitoring and Logs; routes go through routes.software. - schema.graphql re-fetched from test-3043 for the Software* types.
| * two sortable headers (DEVICES / VULNS) so the header indicator and the | ||
| * backend field are the same string. | ||
| */ | ||
| const SORTABLE_COLUMN_IDS = ['devicesCount', 'severity'] as const; |
There was a problem hiding this comment.
🦩 🟠 [warn/recommended] SortInput.field values sent to backend are not validated against SORTABLE_COLUMN_IDS before being passed as sort variable
SORTABLE_COLUMN_IDS is declared as the only values allowed to reach SortInput.field, but the truncated portion of software-table.tsx (not fully visible) needs to actually gate the sort object constructed from URL/searchParam state against this list before passing it as the sort variable to useLazyLoadQuery. If onSortChange or the sort state is derived directly from a header click id without checking membership in SORTABLE_COLUMN_IDS, arbitrary URL-controlled values could reach the GraphQL query's sort.field argument. This is worth confirming since the code comment asserts the invariant is enforced elsewhere in the file, but that logic is outside the visible diff/context excerpt.
Evidence
const SORTABLE_COLUMN_IDS = ['devicesCount', 'severity'] as const;
🤖 Prompt for AI agents
In src/app/(app)/software/components/software-table.tsx around line 41, address this code-review finding: SortInput.field values sent to backend are not validated against SORTABLE_COLUMN_IDS before being passed as sort variable.
SORTABLE_COLUMN_IDS is declared as the only values allowed to reach SortInput.field, but the truncated portion of software-table.tsx (not fully visible) needs to actually gate the sort object constructed from URL/searchParam state against this list before passing it as the `sort` variable to useLazyLoadQuery. If onSortChange or the sort state is derived directly from a header click id without checking membership in SORTABLE_COLUMN_IDS, arbitrary URL-controlled values could reach the GraphQL query's sort.field argument. This is worth confirming since the code comment asserts the invariant is enforced elsewhere in the file, but that logic is outside the visible diff/context excerpt.
The flagged code:
```
const SORTABLE_COLUMN_IDS = ['devicesCount', 'severity'] as const;
```
Make the minimal change that resolves the finding; do not refactor unrelated code.
confidence: 20 — react 👍/👎 to teach the reviewer
🦩 Flamingo Code Review1 finding(s) — 0 action required · 1 recommended · 0 informational Mode: advisory · 1 defect(s) outside any rule React 👍/👎 on inline comments to teach the reviewer. |
… tabs Adds /software/details?id=, built from the Figma detail design: the title block, a Publisher / Type / Latest Version summary card, and the two tabs. - Devices tab: every machine carrying the title, with its own installed version and lifecycle chip (OUTDATED / SCHEDULED UPDATE / UNINSTALLING / SCHEDULED UNINSTALL), a status funnel, version sort, search, and a per-row uninstall behind a confirmation. Machines are read through the existing deviceRowFields_machine ladder step. - Vulnerabilities tab: CVE id, severity chip with its CVSS score, affected version and publication date with the CVE's age; severity funnel, sort on version and published, and a per-row link to the NVD record. - The list rows now open the detail page (row click + the arrow column the design has always shown).
- Install Software page (/software/install): package-manager catalog search (searchPackages), install-now/schedule choice and device picker. "Run Installation" stays disabled: the schema has no install mutation. - Vulnerabilities tab now lists fleet CVEs (vulnerabilities query) instead of vulnerable software titles; severity funnel maps to the minSeverity cut-off. - CVE detail page (/software/vulnerability?id=): description, score, devices, resolved-in, published and the affected software table. - Schema refresh from test-3043: software mutations and Software.type are gone, so the per-device "Uninstall Software" action and the Type summary cell are removed; searchPackages is now a connection.
- Schema refresh from test-3043: installSoftware / updateSoftware take catalog packages, plus software schedules and softwareExecutions. - Install and Update Software share one page (SoftwareActionView): run now via installSoftware / updateSoftware, or schedule via createSoftwareSchedule with the script-schedule date / time / timezone grid. - Software Update Details page (/software/executions): package summary (version, processed devices) over the shared executions table fed by softwareExecutions. - "Update Software" action on the Software Update tab.
Implements the Figma All Software page (node 209-15626) on Relay, against the
softwares(...)connection that just landed in the schema.What's in
/software— one row per software title aggregated across the fleet: search, infinite scroll, server-side sort on DEVICES and VULNS, result count fromfilteredCount.Unknownwhen null) with theOUTDATEDchip and the+N older versionsline; device count; severity tag withN CVEs, or—plusno CPE match./software/updatesand/software/vulnerabilitiesreuse the same table with a fixed scope (versionStatuses: [OUTDATED]/minSeverity: LOW), so the three-tab bar from the design is real navigation.routes.software.*.schema.graphqlre-fetched from test-3043 for theSoftware*types (the rest of the diff there is the backend reorderingMutationfields).Assumptions worth a look
devicesCountandseverityare a guess — the schema documents no sortable fields forsoftwares(sort:), and the resolver isn't live yet, so I couldn't verify. A value outside that pair is clamped away in the URL, so a stale link falls back to the backend order instead of erroring.Deliberately out
installSoftwareneedssoftwareId+machineIds, there is no picker design in this node and no "available software" query —softwareslists what is already installed.software(id),softwareDevices,softwareVulnerabilitiesare waiting in the schema for it).Testing
npm run relay,type-check,prettier,eslint -c eslint.ci.mjson the touched files,next build— all green.Not verified against live data: on test-3043
Query.softwaresreturnsnullin a non-null field (NullValueInNonNullableField), i.e. the SDL is deployed but the resolver isn't. Until it is, the page shows itsContentErrorBoundarystate.