diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f64880a..8e3258a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -37,7 +37,7 @@ Read: ## Prerequisites - Rust `1.90.0` with `rustfmt` and `clippy`; -- Node.js `22` and npm for building the embedded frontend assets; +- Node.js `22.22.0` or newer and npm for building the embedded frontend assets; - Codex `0.144.0` for adapter and App Server compatibility work. ```text diff --git a/README.md b/README.md index a1521f2..dd46c41 100644 --- a/README.md +++ b/README.md @@ -145,8 +145,8 @@ Requirements: - Rust `1.90.0` with `rustfmt` and `clippy`; - Codex `0.144.0` for the currently validated adapter; -- Node.js `22` and npm for building the embedded frontend assets (Node is not - needed at runtime). +- Node.js `22.22.0` or newer and npm for building the embedded frontend assets + (Node is not needed at runtime). ```text cd crates/needle-app/web diff --git a/SECURITY.md b/SECURITY.md index 9101bc1..bb1ad88 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -29,18 +29,10 @@ other sensitive information out of the public issue. For ordinary bugs, regressions, and feature requests, use the normal public issue or pull-request process instead of this security-reporting route. -## Known dependency advisories - -The installed `react-router-dom` version is `7.18.1`, which falls within the -affected range (`>=7.12.0, <8.3.0`) of -[GHSA-qwww-vcr4-c8h2](https://github.com/advisories/GHSA-qwww-vcr4-c8h2). -Upstream describes this advisory as affecting unstable React Server Component -(RSC) APIs. Needle's current Vite client-side SPA uses `BrowserRouter` and -`createRoot` and does not enable those RSC APIs; this bounded non-exposure does -not mean the dependency is generally safe. - -Upstream identifies `8.3.0` as the first patched release, but that release is -not available from npm as of 2026-08-03. This is a temporary, scoped exception, -not evidence of a completed security audit. Do not enable the affected RSC APIs; -monitor for a published patched release, then upgrade and rerun `npm audit`, -tests, lint, and build. Remove this exception once that validation succeeds. +## Resolved dependency advisories + +[GHSA-qwww-vcr4-c8h2](https://github.com/advisories/GHSA-qwww-vcr4-c8h2) +was remediated by migrating the Vite client-side SPA from the removed +`react-router-dom` package to `react-router` `8.3.0`. Needle does not enable the +affected unstable React Server Component (RSC) APIs. This remediation does not +constitute a completed third-party security audit. diff --git a/crates/needle-app/web/package-lock.json b/crates/needle-app/web/package-lock.json index 3ce7431..c3eb188 100644 --- a/crates/needle-app/web/package-lock.json +++ b/crates/needle-app/web/package-lock.json @@ -16,9 +16,9 @@ "clsx": "^2.1.1", "lucide-react": "^1.27.0", "radix-ui": "^1.6.7", - "react": "^19.2.6", - "react-dom": "^19.2.6", - "react-router-dom": "7.18.1", + "react": "^19.2.7", + "react-dom": "^19.2.7", + "react-router": "8.3.0", "recharts": "^3.10.1", "tailwind-merge": "^3.6.0", "tailwindcss": "^4", @@ -3812,18 +3812,11 @@ "dev": true, "license": "MIT" }, - "node_modules/cookie": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", - "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } + "node_modules/cookie-es": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-3.1.1.tgz", + "integrity": "sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==", + "license": "MIT" }, "node_modules/cross-spawn": { "version": "7.0.6", @@ -5658,20 +5651,19 @@ } }, "node_modules/react-router": { - "version": "7.18.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.18.1.tgz", - "integrity": "sha512-GDLgg3i3uM0aeJO3Fm+TCS+sDQ7gu12T6x0qdTEzcwqEfleci7JwugVNIF3U//0FWKnJT7ptG+20B2jfDqnZAg==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-8.3.0.tgz", + "integrity": "sha512-qyPMvW83jGIct3yiieisxdk9M745anqhpIMKN5m1t6yBMfgVPpt77aHOqs5fUlEJRMCGffg9BaQLH9oPVOL7xQ==", "license": "MIT", "dependencies": { - "cookie": "^1.0.1", - "set-cookie-parser": "^2.6.0" + "cookie-es": "^3.1.1" }, "engines": { - "node": ">=20.0.0" + "node": ">=22.22.0" }, "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" + "react": ">=19.2.7", + "react-dom": ">=19.2.7" }, "peerDependenciesMeta": { "react-dom": { @@ -5679,22 +5671,6 @@ } } }, - "node_modules/react-router-dom": { - "version": "7.18.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.18.1.tgz", - "integrity": "sha512-KaZh+X/6UtEp28x51AUYZDMg9NGoz2ja3dNHa+ta/tk40vCzKhQ/RypCWBMLbmDr6//E24Vv5uPsrqXFozdkAg==", - "license": "MIT", - "dependencies": { - "react-router": "7.18.1" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" - } - }, "node_modules/react-style-singleton": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", @@ -5854,12 +5830,6 @@ "semver": "bin/semver.js" } }, - "node_modules/set-cookie-parser": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", - "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", - "license": "MIT" - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", diff --git a/crates/needle-app/web/package.json b/crates/needle-app/web/package.json index f51adf0..9f94020 100644 --- a/crates/needle-app/web/package.json +++ b/crates/needle-app/web/package.json @@ -23,9 +23,9 @@ "clsx": "^2.1.1", "lucide-react": "^1.27.0", "radix-ui": "^1.6.7", - "react": "^19.2.6", - "react-dom": "^19.2.6", - "react-router-dom": "7.18.1", + "react": "^19.2.7", + "react-dom": "^19.2.7", + "react-router": "8.3.0", "recharts": "^3.10.1", "tailwind-merge": "^3.6.0", "tailwindcss": "^4", diff --git a/crates/needle-app/web/src/App.tsx b/crates/needle-app/web/src/App.tsx index de598f8..23768d7 100644 --- a/crates/needle-app/web/src/App.tsx +++ b/crates/needle-app/web/src/App.tsx @@ -1,5 +1,5 @@ import { lazy, Suspense } from "react" -import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom" +import { BrowserRouter, Navigate, Route, Routes } from "react-router" import { AppShell } from "@/components/app-shell" import { Skeleton } from "@/components/ui/skeleton" diff --git a/crates/needle-app/web/src/components/app-shell.tsx b/crates/needle-app/web/src/components/app-shell.tsx index f598c4b..5338d63 100644 --- a/crates/needle-app/web/src/components/app-shell.tsx +++ b/crates/needle-app/web/src/components/app-shell.tsx @@ -20,7 +20,7 @@ import { ShieldCheck, SlidersHorizontal, } from "lucide-react" -import { NavLink, useLocation } from "react-router-dom" +import { NavLink, useLocation } from "react-router" import { useApprovalEvents, useControlPlane } from "@/api" import { diff --git a/crates/needle-app/web/src/pages/changes-page.tsx b/crates/needle-app/web/src/pages/changes-page.tsx index 404ce8e..90e3fce 100644 --- a/crates/needle-app/web/src/pages/changes-page.tsx +++ b/crates/needle-app/web/src/pages/changes-page.tsx @@ -1,6 +1,6 @@ import { type ReactNode, useState } from "react" import { ArrowLeft, FilePenLine } from "lucide-react" -import { Link, useParams } from "react-router-dom" +import { Link, useParams } from "react-router" import { type ChangeAttempt, diff --git a/crates/needle-app/web/src/pages/overview-page.tsx b/crates/needle-app/web/src/pages/overview-page.tsx index 5a9b701..0fc6779 100644 --- a/crates/needle-app/web/src/pages/overview-page.tsx +++ b/crates/needle-app/web/src/pages/overview-page.tsx @@ -8,7 +8,7 @@ import { Server, } from "lucide-react" import type { ReactNode } from "react" -import { Link } from "react-router-dom" +import { Link } from "react-router" import { useControlPlane } from "@/api" import { Empty, EmptyDescription, EmptyHeader, EmptyTitle } from "@/components/ui/empty" diff --git a/crates/needle-app/web/src/pages/resource-page.tsx b/crates/needle-app/web/src/pages/resource-page.tsx index 6ef73a5..266b227 100644 --- a/crates/needle-app/web/src/pages/resource-page.tsx +++ b/crates/needle-app/web/src/pages/resource-page.tsx @@ -10,7 +10,7 @@ import { SlidersHorizontal, } from "lucide-react" import { useState } from "react" -import { useParams } from "react-router-dom" +import { useParams } from "react-router" import { type ControlPlane, diff --git a/docs/DEVELOPER_SETUP.md b/docs/DEVELOPER_SETUP.md index a166db7..bb5abfa 100644 --- a/docs/DEVELOPER_SETUP.md +++ b/docs/DEVELOPER_SETUP.md @@ -7,8 +7,8 @@ run. It is a development workflow, not a supported installation path. - Rust `1.90.0` with `rustfmt` and `clippy`; - Codex `0.144.0` for the currently validated App Server adapter; -- Node.js `22` and npm for building the embedded frontend assets. Node.js is - not needed at runtime. +- Node.js `22.22.0` or newer and npm for building the embedded frontend assets. + Node.js is not needed at runtime. ```text rustup toolchain install 1.90.0 --component rustfmt --component clippy diff --git a/docs/RUNTIME_AND_WEB_CONTROL_PLANE.md b/docs/RUNTIME_AND_WEB_CONTROL_PLANE.md index e70eb79..b04d9a5 100644 --- a/docs/RUNTIME_AND_WEB_CONTROL_PLANE.md +++ b/docs/RUNTIME_AND_WEB_CONTROL_PLANE.md @@ -68,8 +68,9 @@ This is a local development control plane, not a remotely hosted service. - Settings. The frontend uses React, TypeScript, Vite, React Router, TanStack Query, -Tailwind, shadcn/ui patterns, and Recharts. Node.js 22 and npm are required to -build the embedded assets; the running Rust binary does not invoke Node.js. +Tailwind, shadcn/ui patterns, and Recharts. Node.js 22.22.0 or newer and npm are +required to build the embedded assets; the running Rust binary does not invoke +Node.js. ## API groups