Tighten hook and proxy discovery

AI assistance disclosure: Codex implemented and verified these fixes under maintainer direction.
This commit is contained in:
Paul Bakaus
2026-09-02 09:35:01 -07:00
parent be43532192
commit 0e1f94acae
4 changed files with 77 additions and 10 deletions
+6 -8
View File
@@ -1313,13 +1313,11 @@ function hookEnabledAt(root) {
const STOP_REVIEW_PROVIDERS = new Set(['claude-code', 'codex', 'agents', 'grok']);
// Harness project settings are discovered by walking up from the active
// working directory. Context resolution can intentionally select a nested
// product root even when the harness project (and its hook manifest) lives at
// the enclosing git root, so checking only projectRoot/repoRoot produces a
// false MANUAL_DETECTOR_REQUIRED directive. Mirror the ancestor lookup through
// the nearest git boundary, while retaining exact resolved roots for explicit
// targets outside the invoking directory.
// Harness project settings are discovered by walking up from the resolved
// project root. Its hook manifest can live at an enclosing git root, so
// checking only projectRoot/repoRoot produces a false
// MANUAL_DETECTOR_REQUIRED directive. Starting from projectRoot also prevents
// an explicit target from borrowing an unrelated manifest near the caller.
function hookManifestSearchRoots(ctx) {
const roots = [];
const seen = new Set();
@@ -1331,7 +1329,7 @@ function hookManifestSearchRoots(ctx) {
roots.push(resolved);
};
let current = path.resolve(process.cwd());
let current = path.resolve(ctx.projectRoot || process.cwd());
const home = path.resolve(os.homedir());
while (true) {
add(current);
+14 -2
View File
@@ -78,10 +78,12 @@ const NUXT_ROUTE_RULES_SIGNALS = [
/\bscript-src\b/,
];
const NEXT_REQUEST_HOOK_FILES = new Set([
const NEXT_MIDDLEWARE_FILES = new Set([
'middleware.ts',
'middleware.js',
'middleware.mjs',
]);
const NEXT_PROXY_FILES = new Set([
'proxy.ts',
'proxy.js',
'proxy.mjs',
@@ -89,6 +91,16 @@ const NEXT_REQUEST_HOOK_FILES = new Set([
const MIDDLEWARE_HINT = /headers\.set\(\s*["']Content-Security-Policy["']/i;
const META_TAG_HINT = /http-equiv\s*=\s*["']Content-Security-Policy["']/i;
function isNextRequestHookFile(relPath, base) {
if (NEXT_MIDDLEWARE_FILES.has(base)) return true;
if (!NEXT_PROXY_FILES.has(base)) return false;
const normalized = relPath.split(path.sep).join('/').toLowerCase();
// Next.js 16 recognizes proxy at the project root or in the optional src/
// directory, alongside app/ or pages/. A same-named helper deeper in the
// tree is not the framework request hook.
return normalized === base || normalized === `src/${base}`;
}
/**
* @param {string} cwd Project root.
* @returns {{ shape: string|null, signals: string[] }}
@@ -142,7 +154,7 @@ export function detectCsp(cwd = process.cwd()) {
// === detect-only shapes ===
if (NEXT_REQUEST_HOOK_FILES.has(base) && MIDDLEWARE_HINT.test(body)) {
if (isNextRequestHookFile(relPath, base) && MIDDLEWARE_HINT.test(body)) {
hits.middleware.push(relPath);
}