mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-17 08:36:25 +03:00
Fix CSP and hook ancestor discovery
Recognize Next.js 16 proxy files when detecting runtime CSP and mirror harness ancestor lookup when locating active hook manifests for nested projects. AI assistance disclosure: Implemented and verified with Codex under maintainer direction.
This commit is contained in:
@@ -1198,6 +1198,29 @@ describe('context.mjs CLI', () => {
|
||||
assert.match(disabled.stdout, /detect\.mjs --json <changed targets>/);
|
||||
});
|
||||
|
||||
it('finds the active hook manifest at an enclosing harness project root', () => {
|
||||
const scripts = path.join(scratch, 'bundle', 'skills', 'impeccable', 'scripts');
|
||||
stageContextBundle(scripts, { providerId: 'claude-code' });
|
||||
|
||||
const repo = path.join(scratch, 'repo');
|
||||
const project = path.join(repo, 'web');
|
||||
fs.mkdirSync(path.join(repo, '.git'), { recursive: true });
|
||||
fs.mkdirSync(path.join(repo, '.claude'), { recursive: true });
|
||||
fs.mkdirSync(project, { recursive: true });
|
||||
fs.writeFileSync(path.join(project, 'PRODUCT.md'), '# Nested web product\n');
|
||||
fs.writeFileSync(path.join(repo, '.claude', 'settings.local.json'), JSON.stringify({
|
||||
hooks: { Stop: [{ hooks: [{ command: 'node .claude/skills/impeccable/scripts/hook.mjs' }] }] },
|
||||
}));
|
||||
|
||||
const res = spawnSync(process.execPath, [path.join(scripts, 'context.mjs')], {
|
||||
cwd: project,
|
||||
encoding: 'utf8',
|
||||
env: { ...process.env, IMPECCABLE_NO_UPDATE_CHECK: '1', IMPECCABLE_NO_STALENESS_CHECK: '1' },
|
||||
});
|
||||
assert.equal(res.status, 0, res.stderr);
|
||||
assert.doesNotMatch(res.stdout, /MANUAL_DETECTOR_REQUIRED:/);
|
||||
});
|
||||
|
||||
it('adds no detector directive when a per-edit-only hook is active', () => {
|
||||
const scripts = path.join(scratch, 'bundle', 'skills', 'impeccable', 'scripts');
|
||||
stageContextBundle(scripts, { providerId: 'cursor' });
|
||||
|
||||
@@ -94,6 +94,9 @@ Fixtures can also opt into a **runtime E2E** pass that actually installs depende
|
||||
}
|
||||
```
|
||||
|
||||
The legacy `middleware` shape name covers CSP set in either Next.js
|
||||
`middleware.*` files or the Next.js 16 `proxy.*` convention.
|
||||
|
||||
The `expectedAfter` file lives alongside `fixture.json` (not inside `files/`) and is a human/agent-review reference — tests don't auto-apply the patch.
|
||||
|
||||
The `runtime` block is optional. Fixtures without it only run the static unit checks (is-generated, inject, wrap, csp-detect). Fixtures *with* it additionally run the E2E suite in `tests/live-e2e.test.mjs` (`bun run test:live-e2e`), which:
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
export default function RootLayout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { NextResponse, type NextRequest } from "next/server";
|
||||
|
||||
export function proxy(request: NextRequest) {
|
||||
const response = NextResponse.next({ request });
|
||||
response.headers.set(
|
||||
"Content-Security-Policy",
|
||||
"default-src 'self'; script-src 'self' 'nonce-runtime'; connect-src 'self'",
|
||||
);
|
||||
return response;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "Next.js 16 (proxy CSP)",
|
||||
"config": {
|
||||
"files": ["app/layout.tsx"],
|
||||
"insertBefore": "</body>",
|
||||
"commentSyntax": "jsx"
|
||||
},
|
||||
"sourceFiles": ["proxy.ts", "app/layout.tsx"],
|
||||
"generatedFiles": [],
|
||||
"wrapCases": [],
|
||||
"csp": {
|
||||
"shape": "middleware",
|
||||
"signals": ["proxy.ts:Content-Security-Policy"]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
node_modules/
|
||||
.next/
|
||||
out/
|
||||
Reference in New Issue
Block a user