fix(deps): bump next 15.0.3 → 16.2.6 to clear trivy CVEs
ci / shared (pull_request) Successful in 3s
ci / test (pull_request) Has been skipped
ci / e2e (pull_request) Has been skipped
ci / image (pull_request) Has been skipped

trivy fs scan failed the M0.2 CI gate on the skeleton commit because
next 15.0.3 has 9 known vulns (CRITICAL CVE-2025-29927 auth bypass in
middleware, plus 7 HIGH advisories). 16.2.6 is current latest and
covers every fixed-version range trivy listed.

Side effects of the major bump:
- next 16 dropped 'next lint' — switched the lint script to call eslint
  directly ('eslint . --max-warnings 0').
- eslint-config-next 16 ships flat-config exports natively, so
  eslint.config.mjs imports core-web-vitals + typescript directly
  (no FlatCompat shim, no @eslint/eslintrc dep).
- Typed vi.fn<typeof fetch>() in tenant-registry.test to satisfy
  stricter tuple inference under the new types.

All 4 gates green locally:
  pnpm lint / typecheck / test --coverage (100% on src/lib) / build

Refs: M5.1 (skeleton)
This commit is contained in:
2026-05-18 23:03:49 +02:00
parent cd4b6720d8
commit c051ae0626
8 changed files with 555 additions and 249 deletions
+2 -1
View File
@@ -6,7 +6,8 @@ Generated section is appended on release tag via `git-cliff` (see `.gitea/workfl
## [Unreleased]
### Added
- feat(app): Next.js 15 + Auth.js v5 skeleton with host→slug middleware, tenant context layout, OIDC sign-in flow
- chore(deps): bump next + eslint-config-next to 16.2.6 to clear trivy CVEs (CVE-2025-29927 critical + 7 highs in next 15.0.3)
- feat(app): Next.js 16 + Auth.js v5 skeleton with host→slug middleware, tenant context layout, OIDC sign-in flow
-
### Changed
+3 -3
View File
@@ -1,6 +1,6 @@
# portal
Next.js 15 customer area + backstage.
Next.js 16 customer area + backstage.
> Part of the **Breakpilot Platform**. For the big picture see [`platform/docs`](https://gitea.meghsakha.com/platform/docs):
> [Architecture](https://gitea.meghsakha.com/platform/docs/src/branch/main/PLATFORM_ARCHITECTURE.md) ·
@@ -10,7 +10,7 @@ Next.js 15 customer area + backstage.
## What this is
Next.js 15 customer area + backstage. Scaffolded under milestone M5.1. See [`platform/docs`](https://gitea.meghsakha.com/platform/docs) for the full architecture context.
Next.js 16 customer area + backstage. Scaffolded under milestone M5.1. See [`platform/docs`](https://gitea.meghsakha.com/platform/docs) for the full architecture context.
**Plane:** Control
**Owner:** @sharang
@@ -38,7 +38,7 @@ make dev # next dev on http://localhost:3000
Seed login (from the dev-stack realm): `test@breakpilot.dev` / `test`.
`make test` / `make lint` / `make typecheck` / `make build` run vitest / next lint / tsc / next build respectively.
`make test` / `make lint` / `make typecheck` / `make build` run vitest / eslint / tsc / next build respectively.
Env vars live in `.env.example`. Copy to `.env.local` for local overrides (gitignored).
+6 -10
View File
@@ -1,16 +1,12 @@
import { dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { FlatCompat } from "@eslint/eslintrc";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const compat = new FlatCompat({ baseDirectory: __dirname });
// eslint-config-next v16 ships flat-config exports natively; no FlatCompat shim.
import nextWebVitals from "eslint-config-next/core-web-vitals";
import nextTypescript from "eslint-config-next/typescript";
const config = [
...compat.extends("next/core-web-vitals", "next/typescript"),
...nextWebVitals,
...nextTypescript,
{
ignores: [".next/**", "node_modules/**", "coverage/**"],
ignores: [".next/**", "node_modules/**", "coverage/**", "next-env.d.ts"],
},
];
+2 -1
View File
@@ -1,5 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
import "./.next/types/routes.d.ts";
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
+4 -5
View File
@@ -2,7 +2,7 @@
"name": "@breakpilot/portal",
"version": "0.0.0",
"private": true,
"description": "Customer-facing portal + platform-staff backstage. Next.js 15 + Auth.js v5.",
"description": "Customer-facing portal + platform-staff backstage. Next.js + Auth.js v5.",
"license": "UNLICENSED",
"engines": {
"node": ">=20",
@@ -12,24 +12,23 @@
"dev": "next dev --port 3000",
"build": "next build",
"start": "next start --port 3000",
"lint": "next lint --max-warnings 0",
"lint": "eslint . --max-warnings 0",
"typecheck": "tsc --noEmit",
"test": "vitest run --coverage"
},
"dependencies": {
"next": "15.0.3",
"next": "16.2.6",
"next-auth": "5.0.0-beta.25",
"react": "19.0.0",
"react-dom": "19.0.0"
},
"devDependencies": {
"@eslint/eslintrc": "^3.3.5",
"@types/node": "20.16.10",
"@types/react": "19.0.1",
"@types/react-dom": "19.0.1",
"@vitest/coverage-v8": "2.1.8",
"eslint": "9.15.0",
"eslint-config-next": "15.0.3",
"eslint-config-next": "16.2.6",
"typescript": "5.7.2",
"vitest": "2.1.8"
}
+509 -221
View File
File diff suppressed because it is too large Load Diff
+4 -2
View File
@@ -54,9 +54,11 @@ describe("fetchTenantBySlug", () => {
});
test("encodes slug to defend against weird input", async () => {
const fetchSpy = vi.fn(async () => new Response("", { status: 404 }));
const fetchSpy = vi.fn<typeof fetch>(async () => new Response("", { status: 404 }));
globalThis.fetch = fetchSpy;
await fetchTenantBySlug("a/b c");
expect(fetchSpy.mock.calls[0][0]).toBe("http://test:1234/v1/tenants/by-slug/a%2Fb%20c");
const firstCall = fetchSpy.mock.calls[0];
expect(firstCall).toBeDefined();
expect(firstCall![0]).toBe("http://test:1234/v1/tenants/by-slug/a%2Fb%20c");
});
});
+25 -6
View File
@@ -1,7 +1,11 @@
{
"compilerOptions": {
"target": "ES2022",
"lib": ["dom", "dom.iterable", "esnext"],
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": false,
"skipLibCheck": true,
"strict": true,
@@ -11,14 +15,29 @@
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"jsx": "react-jsx",
"incremental": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
"@/*": [
"src/*"
]
},
"plugins": [{ "name": "next" }]
"plugins": [
{
"name": "next"
}
]
},
"include": ["next-env.d.ts", "src/**/*.ts", "src/**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules", ".next"]
"include": [
"next-env.d.ts",
"src/**/*.ts",
"src/**/*.tsx",
".next/types/**/*.ts",
".next/dev/types/**/*.ts"
],
"exclude": [
"node_modules",
".next"
]
}