From 2f92eede8cdeb1c8939294b82d1c29bac642b55c Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 20 Jul 2026 22:52:31 +0000 Subject: [PATCH 1/2] =?UTF-8?q?build(deps-dev):=20@babel/parser=207?= =?UTF-8?q?=E2=86=928=20(+compat)=20and=20pin=20@supabase/supabase-js=20fl?= =?UTF-8?q?oor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves two open Dependabot dependency PRs. @babel/parser ^7.29.7 → ^8.0.4 (dev, PR #991) - Babel 8 models dynamic `import(...)` as an ESTree-aligned ImportExpression (specifier in `source`, attributes in `options`) instead of a CallExpression whose callee is an `Import` node. Teach the architecture-boundaries import graph both shapes so dynamic-import edges keep resolving. - Babel 8 parses import attributes by default and removed the standalone "importAttributes" parser plugin (now a type error). Drop it from the two test parsers; attribute parsing behaviour is unchanged. @supabase/supabase-js ^2.108.2 → ^2.110.7 (prod, supersedes PR #945) - 2.110.7 is already the resolved/installed version under the old floor; this only lifts the declared floor to match reality. The client-bundle secret scanner already masks matches and already ignores supabase-js's bare `sb_secret_` prefix literal (its regex requires a 20+ char token), so the stale scanner rewrite in PR #945 is intentionally not taken — it would regress the newer masking on main. Lockfile is regenerated with the repo-pinned npm@11.17.0 (packageManager) so platform-optional entries (@emnapi/core, @emnapi/runtime) are preserved; an older npm prunes them and breaks `npm ci` in CI. Verification (offline): typecheck, full unit suite (no new failures vs the pre-existing pdf-extraction-budget sandbox flake), lint, knip, production build + client-bundle-secrets scan, and `npm@11.17.0 ci --dry-run` all green. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01TVVgc9PtHfj1aUQX387P8y --- package-lock.json | 144 ++++++++++++++++++++++++-- package.json | 4 +- tests/architecture-boundaries.test.ts | 45 +++++--- tests/client-secret-surface.test.ts | 4 +- 4 files changed, 171 insertions(+), 26 deletions(-) diff --git a/package-lock.json b/package-lock.json index 01107e77b..8ace7948b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "dependencies": { "@next/env": "16.2.10", "@supabase/ssr": "^0.12.3", - "@supabase/supabase-js": "^2.108.2", + "@supabase/supabase-js": "^2.110.7", "exceljs": "^4.4.0", "jszip": "^3.10.1", "lucide-react": "^1.25.0", @@ -30,7 +30,7 @@ }, "devDependencies": { "@axe-core/playwright": "^4.12.1", - "@babel/parser": "^7.29.7", + "@babel/parser": "^8.0.4", "@next/bundle-analyzer": "^16.2.10", "@tailwindcss/postcss": "^4.3.3", "@testing-library/dom": "^10.4.1", @@ -201,6 +201,22 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/generator": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", @@ -218,6 +234,22 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/generator/node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/helper-compilation-targets": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", @@ -322,19 +354,53 @@ } }, "node_modules/@babel/parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", - "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.4.tgz", + "integrity": "sha512-srpptsAkEbbNIC/q8nT7o+m6CQe8CJUTV/t7MYc9NnWlgYVtHOb7JH6SorxMhN0kuRJjVqXbKClG6xSbPtzz+g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.29.7" + "@babel/types": "^8.0.4" }, "bin": { "parser": "bin/babel-parser.js" }, "engines": { - "node": ">=6.0.0" + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/parser/node_modules/@babel/helper-string-parser": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.0.tgz", + "integrity": "sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/parser/node_modules/@babel/helper-validator-identifier": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz", + "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/parser/node_modules/@babel/types": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.4.tgz", + "integrity": "sha512-eY+Yn3dCqTGmyiq2QRU66lA5FL8lqqqvecHt0fF3uHONIa7ToYsaCiWV8lOKqAs0Rb2SjixiKFROngnulPtt2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^8.0.0", + "@babel/helper-validator-identifier": "^8.0.4" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" } }, "node_modules/@babel/runtime": { @@ -362,6 +428,22 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/template/node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/traverse": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", @@ -381,6 +463,22 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/traverse/node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/types": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", @@ -6528,6 +6626,22 @@ "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" } }, + "node_modules/eslint-plugin-react-hooks/node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/eslint-scope": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", @@ -8738,6 +8852,22 @@ "source-map-js": "^1.2.1" } }, + "node_modules/magicast/node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/make-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", diff --git a/package.json b/package.json index 7bce24b72..1474baa34 100644 --- a/package.json +++ b/package.json @@ -182,7 +182,7 @@ "dependencies": { "@next/env": "16.2.10", "@supabase/ssr": "^0.12.3", - "@supabase/supabase-js": "^2.108.2", + "@supabase/supabase-js": "^2.110.7", "exceljs": "^4.4.0", "jszip": "^3.10.1", "lucide-react": "^1.25.0", @@ -206,7 +206,7 @@ }, "devDependencies": { "@axe-core/playwright": "^4.12.1", - "@babel/parser": "^7.29.7", + "@babel/parser": "^8.0.4", "@next/bundle-analyzer": "^16.2.10", "@tailwindcss/postcss": "^4.3.3", "@testing-library/dom": "^10.4.1", diff --git a/tests/architecture-boundaries.test.ts b/tests/architecture-boundaries.test.ts index 1e4d6ec74..aeffe7a33 100644 --- a/tests/architecture-boundaries.test.ts +++ b/tests/architecture-boundaries.test.ts @@ -23,7 +23,9 @@ function sourceFiles() { function parseModuleSource(sourceText: string) { return parse(sourceText, { sourceType: "module", - plugins: ["jsx", "typescript", "importAttributes"], + // @babel/parser 8 parses import attributes by default; the standalone + // "importAttributes" plugin was removed (and is now a type error). + plugins: ["jsx", "typescript"], }); } @@ -60,9 +62,33 @@ function moduleSpecifiersFromSource(_filePath: string, sourceText: string) { } } + const addDynamicSpecifier = (moduleSpecifier: Record | undefined) => { + if (!moduleSpecifier) return; + if (moduleSpecifier.type === "StringLiteral" && typeof moduleSpecifier.value === "string") { + dynamicImports.add(moduleSpecifier.value); + } else if ( + moduleSpecifier.type === "TemplateLiteral" && + Array.isArray(moduleSpecifier.expressions) && + moduleSpecifier.expressions.length === 0 && + Array.isArray(moduleSpecifier.quasis) && + moduleSpecifier.quasis.length === 1 + ) { + const cooked = ((moduleSpecifier.quasis[0] as Record).value as Record)?.cooked; + if (typeof cooked === "string") dynamicImports.add(cooked); + } + }; + const visit = (node: unknown) => { if (!node || typeof node !== "object") return; const current = node as Record; + // @babel/parser 8 models dynamic `import(...)` as an ESTree-aligned + // ImportExpression (specifier in `source`, import-attributes in `options`). + // @babel/parser 7 modelled it as a CallExpression whose callee is an + // `Import` node with the specifier in `arguments[0]`. Handle both shapes so + // this boundary graph stays parser-major agnostic. + if (current.type === "ImportExpression") { + addDynamicSpecifier(current.source as Record | undefined); + } const argumentsList = Array.isArray(current.arguments) ? current.arguments : null; if ( current.type === "CallExpression" && @@ -71,21 +97,8 @@ function moduleSpecifiersFromSource(_filePath: string, sourceText: string) { (argumentsList.length === 1 || argumentsList.length === 2) ) { const callee = current.callee as Record; - const moduleSpecifier = argumentsList[0] as Record | undefined; - if (callee.type === "Import" && moduleSpecifier) { - if (moduleSpecifier.type === "StringLiteral" && typeof moduleSpecifier.value === "string") { - dynamicImports.add(moduleSpecifier.value); - } else if ( - moduleSpecifier.type === "TemplateLiteral" && - Array.isArray(moduleSpecifier.expressions) && - moduleSpecifier.expressions.length === 0 && - Array.isArray(moduleSpecifier.quasis) && - moduleSpecifier.quasis.length === 1 - ) { - const cooked = ((moduleSpecifier.quasis[0] as Record).value as Record) - ?.cooked; - if (typeof cooked === "string") dynamicImports.add(cooked); - } + if (callee.type === "Import") { + addDynamicSpecifier(argumentsList[0] as Record | undefined); } } for (const value of Object.values(current)) { diff --git a/tests/client-secret-surface.test.ts b/tests/client-secret-surface.test.ts index 9db8dcf02..39b816ced 100644 --- a/tests/client-secret-surface.test.ts +++ b/tests/client-secret-surface.test.ts @@ -58,7 +58,9 @@ function localImports(file: string) { const text = readFileSync(file, "utf8"); const source = parse(text, { sourceType: "module", - plugins: ["jsx", "typescript", "importAttributes"], + // @babel/parser 8 parses import attributes by default; the standalone + // "importAttributes" plugin was removed (and is now a type error). + plugins: ["jsx", "typescript"], }); const specifiers: string[] = []; for (const statement of source.program.body) { From 02920b72f912d1ba43a8b319136a0b389b8508a6 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 20 Jul 2026 23:34:30 +0000 Subject: [PATCH 2/2] build(deps): remediate brace-expansion ReDoS to clear the dependency-audit gate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The repo's "Dependency audit (blocking on dependency changes)" CI step runs `npm audit --omit=dev --audit-level=high` and hard-blocks only when a PR touches the manifest/lockfile. main carries a pre-existing high-severity brace-expansion advisory (GHSA-3jxr-9vmj-r5cp, ReDoS) ungated, but any dependency PR — including this one — must clear it to merge. Fix surgically via per-major overrides so each consumer keeps its major and only takes the security patch (no cross-major upgrade, minimal regression surface): - brace-expansion@1 1.1.14 -> 1.1.16 - brace-expansion@2 2.1.0 -> 2.1.2 `npm audit --omit=dev --audit-level=high` now reports 0 vulnerabilities. Lockfile regenerated with the pinned npm@11.17.0 (optional @emnapi/* deps retained). typecheck and the full unit suite are unchanged (no new failures vs the pre-existing pdf-extraction-budget sandbox flake). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01TVVgc9PtHfj1aUQX387P8y --- package-lock.json | 12 ++++++------ package.json | 4 +++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8ace7948b..de727fc39 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5080,9 +5080,9 @@ "license": "MIT" }, "node_modules/brace-expansion": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -10173,9 +10173,9 @@ } }, "node_modules/readdir-glob/node_modules/brace-expansion": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", - "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.2.tgz", + "integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" diff --git a/package.json b/package.json index 1474baa34..b18e9944e 100644 --- a/package.json +++ b/package.json @@ -202,7 +202,9 @@ "postcss": "^8.5.15", "esbuild": "0.28.1", "tmp": "^0.2.7", - "uuid": "^11.1.1" + "uuid": "^11.1.1", + "brace-expansion@1": "^1.1.16", + "brace-expansion@2": "^2.1.2" }, "devDependencies": { "@axe-core/playwright": "^4.12.1",