mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-12 14:16:28 +03:00
Real-world tests (EAC Next turborepo) confirmed that CSP is the common
blocker for live mode. Adds setup-time detection with a one-time user
consent flow — the patch becomes a permanent, dev-guarded entry in the
user's own config, not a transient add/remove.
## Changes
- New detect-csp.mjs helper: grep-based classifier returning
{ shape, signals }. Shape is one of:
- "shared-helper" (monorepo CSP helper with additional*Src arrays)
- "inline-headers" (literal CSP string in headers())
- "middleware" (response.headers.set in middleware.ts; detect-only v1)
- "meta-tag" (<meta http-equiv>; detect-only v1)
- null (no CSP)
Max depth 6, skips node_modules / build / cache dirs, 64KB per file.
- cspChecked boolean on config.json. First-run setup runs detection;
subsequent runs skip. Users re-trigger by deleting the flag.
Validator accepts it.
- Skill live.md gains:
- CSP detection step in first-time setup (gated by cspChecked)
- Consent-prompt template (so every agent phrases it the same way)
- Shape 1 patch template: append `...__impeccableLiveDev` to
additionalScriptSrc/additionalConnectSrc in the app's config
- Shape 2 patch template: two-point edit — declare a dev-only
variable, interpolate into script-src and connect-src in the
CSP literal string
- Troubleshooting note for "said no but now live doesn't work"
## Fixtures
- nextjs-turborepo/: Turborepo shape (shared CSP helper with
additionalScriptSrc options). Sanitized from a real monorepo so the
patch mechanics get tested against realistic layering. Includes
expected-after-patch.ts for human/agent review.
- nextjs-inline-csp/: app-level next.config.js with a literal CSP
string. Includes expected-after-patch.js showing the Shape 2 edit.
## Tests
Framework-fixture harness extended with a detect-csp shape-classification
assertion per fixture. 42 tests across 7 fixtures pass. Clean fixtures
(vite-react, nextjs-app, astro, sveltekit, multipage-with-generator)
correctly return shape: null.
## Deliberately not doing
- No patches[] array, no marker-based rollback, no add/remove lifecycle.
The patch is a permanent dev-guarded config line — the same kind of
edit a user would make themselves.
- No base URL rewriting or proxy mechanism. Script tag still points at
localhost:8400; CSP permits it once patched. No browser-side changes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
34 lines
1.0 KiB
JavaScript
34 lines
1.0 KiB
JavaScript
// Reference output for agent/human review — not executed by tests.
|
|
// After the Shape 2 (inline-headers) CSP patch is applied, next.config.js
|
|
// should look like this.
|
|
|
|
/** @type {import('next').NextConfig} */
|
|
|
|
// Dev-only allowance so impeccable live mode can load. Empty string in any
|
|
// non-development environment.
|
|
const __impeccableLiveDev =
|
|
process.env.NODE_ENV === "development" ? " http://localhost:8400" : "";
|
|
|
|
module.exports = {
|
|
async headers() {
|
|
return [
|
|
{
|
|
source: "/(.*)",
|
|
headers: [
|
|
{
|
|
key: "Content-Security-Policy",
|
|
value:
|
|
"default-src 'self'; " +
|
|
`script-src 'self' 'unsafe-inline' 'unsafe-eval'${__impeccableLiveDev}; ` +
|
|
"style-src 'self' 'unsafe-inline'; " +
|
|
"img-src 'self' data: blob:; " +
|
|
`connect-src 'self'${__impeccableLiveDev}; ` +
|
|
"frame-ancestors 'self';",
|
|
},
|
|
{ key: "X-Frame-Options", value: "SAMEORIGIN" },
|
|
],
|
|
},
|
|
];
|
|
},
|
|
};
|