cuonztech-privacy-chaos-gate 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/types/index.ts","../src/config/index.ts","../src/core/scanner/index.ts","../src/core/scanner/trackerDatabase.ts","../src/core/scanner/bannerLocators.ts","../src/core/remediation/index.ts","../src/core/remediation/reviewer.ts","../src/core/legal/disclaimer.ts","../src/core/remediation/pullRequest.ts","../src/core/legal/jurisdictions.ts","../src/core/report/evidenceReport.ts","../src/core/report/deluxePdf.ts","../src/core/orchestrator.ts"],"sourcesContent":["import { z } from \"zod\";\n\n/**\n * Chaos test scenarios as defined in PRD Section 2B\n */\nexport const ChaosScenarioSchema = z.enum([\n \"happy-path-denied\",\n \"happy-path-accepted\",\n \"fast-click\",\n \"state-manipulation\",\n \"network-drop\",\n \"consent-revoked\",\n \"category-selective\",\n \"consent-persistence\",\n \"banner-ignored\",\n \"subpage-spa\",\n \"cmp-failure\",\n \"embed-leaks\",\n \"consent-mode-v2\",\n \"duplicate-events\",\n \"mobile-usability\",\n]);\n\nexport type ChaosScenario = z.infer<typeof ChaosScenarioSchema>;\n\n/**\n * Evidence status: «nicht prüfbar» ist bewusst kein grünes Häkchen.\n */\nexport const EvidenceStatusSchema = z.enum([\"passed\", \"suspicious\", \"not-checkable\", \"not-applicable\"]);\nexport type EvidenceStatus = z.infer<typeof EvidenceStatusSchema>;\n\nexport const StorageSnapshotSchema = z.object({\n cookies: z.array(z.string()),\n localStorageKeys: z.array(z.string()),\n sessionStorageKeys: z.array(z.string()),\n /** Consent-relevante Einträge mit Wert — zeigt erlaubt/abgelehnt */\n localStorageEntries: z\n .array(z.object({ key: z.string(), value: z.string() }))\n .optional(),\n});\nexport type StorageSnapshot = z.infer<typeof StorageSnapshotSchema>;\n\nexport const RequestEventSchema = z.object({\n at: z.string(),\n url: z.string(),\n trackerName: z.string().optional(),\n trackerCategory: z.string().optional(),\n phase: z.enum([\n \"pre-consent\",\n \"post-accept\",\n \"post-reject\",\n \"post-selection\",\n \"post-revoke\",\n \"post-wipe\",\n \"post-reject-restart\",\n \"other\",\n ]),\n});\nexport type RequestEvent = z.infer<typeof RequestEventSchema>;\n\n/**\n * Beweisreport je Szenario: Auswahl, Timeline, Storage vorher/nachher.\n * Wird in LeakReport.evidence abgelegt (JSON) und optional als Screenshot gespeichert.\n */\nexport const EvidenceRecordSchema = z.object({\n scenario: ChaosScenarioSchema,\n status: EvidenceStatusSchema,\n note: z.string(),\n actionSequence: z.array(z.string()),\n /** Zeitstempel je Aktion, parallel zu actionSequence */\n actionTimeline: z\n .array(z.object({ at: z.string(), action: z.string() }))\n .optional(),\n requestTimeline: z.array(RequestEventSchema),\n storageBefore: StorageSnapshotSchema,\n storageAfter: StorageSnapshotSchema,\n /** Storage-Höhepunkt nach Accept (vor Widerruf) für den echten Widerruf-Diff */\n storageAfterAccept: StorageSnapshotSchema.optional(),\n residualAfterRevoke: z.array(z.string()).optional(),\n /** Pfade zu Screenshots (Auswahl, Banner, nach Aktion) */\n screenshots: z\n .array(z.object({ label: z.string(), path: z.string(), at: z.string() }))\n .optional(),\n screenshotPath: z.string().optional(),\n targetUrl: z.string(),\n checkedAt: z.string(),\n});\nexport type EvidenceRecord = z.infer<typeof EvidenceRecordSchema>;\n\n/**\n * Tracker category classification\n */\nexport const TrackerCategorySchema = z.enum([\n \"analytics\",\n \"marketing\",\n \"functional\",\n \"unknown\",\n]);\n\nexport type TrackerCategory = z.infer<typeof TrackerCategorySchema>;\n\n/**\n * Detailed representation of a detected tracker violation (leak)\n */\nexport const TrackerViolationSchema = z.object({\n id: z.string(),\n scenario: ChaosScenarioSchema,\n trackerName: z.string(),\n trackerCategory: TrackerCategorySchema,\n requestUrl: z.string(),\n /** Verletzte Regel — steuert Gate-Wortlaut und Empfehlungen */\n ruleId: z.string().optional(),\n method: z.string().default(\"GET\"),\n timestamp: z.string(),\n domContext: z\n .object({\n triggerElement: z.string().optional(),\n consentBannerVisible: z.boolean().optional(),\n scriptsFound: z.array(z.string()).optional(),\n })\n .optional(),\n description: z.string(),\n});\n\nexport type TrackerViolation = z.infer<typeof TrackerViolationSchema>;\n\n/**\n * Complete structured report generated by the chaos scanner\n */\nexport const LeakReportSchema = z.object({\n targetUrl: z.string().url(),\n scannedAt: z.string(),\n durationMs: z.number(),\n totalViolations: z.number(),\n violations: z.array(TrackerViolationSchema),\n passedScenarios: z.array(ChaosScenarioSchema),\n failedScenarios: z.array(ChaosScenarioSchema),\n summary: z.string(),\n evidence: z.array(EvidenceRecordSchema).optional(),\n});\n\nexport type LeakReport = z.infer<typeof LeakReportSchema>;\n\n/**\n * Patch proposal produced by the remediation engine\n */\nexport const FilePatchSchema = z.object({\n filePath: z.string(),\n originalContent: z.string().optional(),\n patchedContent: z.string(),\n diff: z.string().optional(),\n explanation: z.string(),\n});\n\nexport type FilePatch = z.infer<typeof FilePatchSchema>;\n\n/**\n * Review verdict produced by the Review Agent before code is committed / PR created\n */\nexport const ReviewVerdictSchema = z.object({\n passed: z.boolean(),\n score: z.number().min(0).max(100),\n comments: z.array(z.string()),\n approvedPatches: z.array(FilePatchSchema),\n rejectedPatches: z.array(FilePatchSchema),\n});\n\nexport type ReviewVerdict = z.infer<typeof ReviewVerdictSchema>;\n\n/**\n * Result of Pull Request generation\n */\nexport const PullRequestResultSchema = z.object({\n branchName: z.string(),\n title: z.string(),\n body: z.string(),\n prNumber: z.number().optional(),\n prUrl: z.string().optional(),\n simulated: z.boolean().default(false),\n});\n\nexport type PullRequestResult = z.infer<typeof PullRequestResultSchema>;\n\nexport const RemediationResultSchema = z.object({\n success: z.boolean(),\n patches: z.array(FilePatchSchema),\n reviewVerdict: ReviewVerdictSchema.optional(),\n commitHash: z.string().optional(),\n commitMessage: z.string().optional(),\n pullRequest: PullRequestResultSchema.optional(),\n error: z.string().optional(),\n});\n\nexport type RemediationResult = z.infer<typeof RemediationResultSchema>;\n\n/**\n * Privacy Gate CLI & Configuration Options\n */\nexport const GateConfigSchema = z.object({\n targetUrl: z.string().url({ message: \"Invalid target URL\" }),\n apiKey: z.string().optional(),\n llmProvider: z.enum([\"openai\", \"anthropic\", \"gemini\"]).default(\"openai\"),\n llmModel: z.string().default(\"gpt-4o\"),\n autoFix: z.boolean().default(true),\n failOnLeak: z.boolean().default(true),\n reportOutput: z.string().default(\"reports/privacy-chaos-report.json\"),\n sourceDir: z.string().default(\".\"),\n gitCommit: z.boolean().default(false),\n createPr: z.boolean().default(false),\n githubToken: z.string().optional(),\n baseBranch: z.string().optional(),\n branchPrefix: z.string().default(\"fix/cpcg-privacy\"),\n /** Optional: nur diese Szenarien ausführen (leer = alle). Für Tests/CI gezielt. */\n scenarios: z.array(ChaosScenarioSchema).optional(),\n /** Demo-Lauf mit synthetischen Testdaten — Report wird gekennzeichnet */\n demo: z.boolean().optional(),\n /** Deluxe-PDF (Deckblatt + Evidence) nach dem Scan erzeugen */\n reportPdf: z.boolean().optional(),\n /** Kundenname für das PDF-Deckblatt */\n clientName: z.string().optional(),\n headless: z.boolean().default(true),\n timeoutMs: z.number().default(30000),\n});\n\nexport type GateConfig = z.infer<typeof GateConfigSchema>;\n\n/**\n * Overall pipeline outcome\n */\nexport interface GateExecutionResult {\n report: LeakReport;\n remediation?: RemediationResult;\n status: \"clean\" | \"remediated\" | \"blocked\" | \"error\";\n exitCode: number;\n}\n","import { config as loadDotenv } from \"dotenv\";\nimport { GateConfig, GateConfigSchema } from \"../types/index.js\";\n\nloadDotenv();\n\nexport interface CliRawOptions {\n reportPdf?: boolean | string;\n client?: string;\n demo?: boolean | string;\n url?: string;\n apiKey?: string;\n llmProvider?: string;\n llmModel?: string;\n autoFix?: string | boolean;\n failOnLeak?: string | boolean;\n reportOutput?: string;\n sourceDir?: string;\n gitCommit?: string | boolean;\n createPr?: string | boolean;\n githubToken?: string;\n branchPrefix?: string;\n baseBranch?: string;\n headless?: string | boolean;\n timeoutMs?: string | number;\n}\n\nfunction parseBoolean(val: unknown, defaultVal: boolean): boolean {\n if (typeof val === \"boolean\") return val;\n if (typeof val === \"string\") {\n const lower = val.toLowerCase().trim();\n if (lower === \"true\" || lower === \"1\" || lower === \"yes\") return true;\n if (lower === \"false\" || lower === \"0\" || lower === \"no\") return false;\n }\n return defaultVal;\n}\n\nexport function resolveGateConfig(cliOptions: CliRawOptions): GateConfig {\n const merged = {\n targetUrl: cliOptions.url || process.env.CPCG_TARGET_URL || process.env.STAGING_URL || \"\",\n apiKey:\n cliOptions.apiKey ||\n process.env.CPCG_LLM_API_KEY ||\n process.env.OPENAI_API_KEY ||\n process.env.ANTHROPIC_API_KEY ||\n process.env.GEMINI_API_KEY ||\n \"\",\n llmProvider:\n cliOptions.llmProvider ||\n process.env.CPCG_LLM_PROVIDER ||\n \"openai\",\n llmModel:\n cliOptions.llmModel ||\n process.env.CPCG_LLM_MODEL ||\n \"gpt-4o\",\n autoFix: parseBoolean(\n cliOptions.autoFix ?? process.env.CPCG_AUTO_FIX,\n true\n ),\n failOnLeak: parseBoolean(\n cliOptions.failOnLeak ?? process.env.CPCG_FAIL_ON_LEAK,\n true\n ),\n reportOutput:\n cliOptions.reportOutput ||\n process.env.CPCG_REPORT_OUTPUT ||\n \"reports/privacy-chaos-report.json\",\n sourceDir:\n cliOptions.sourceDir ||\n process.env.CPCG_SOURCE_DIR ||\n \".\",\n gitCommit: parseBoolean(\n cliOptions.gitCommit ?? process.env.CPCG_GIT_COMMIT,\n false\n ),\n createPr: parseBoolean(\n cliOptions.createPr ?? process.env.CPCG_CREATE_PR,\n false\n ),\n reportPdf: parseBoolean(cliOptions.reportPdf ?? process.env.CPCG_REPORT_PDF, false),\n demo: parseBoolean(cliOptions.demo ?? process.env.CPCG_DEMO, false),\n clientName: cliOptions.client || process.env.CPCG_CLIENT_NAME || undefined,\n githubToken:\n cliOptions.githubToken ||\n process.env.GITHUB_TOKEN ||\n process.env.GH_TOKEN ||\n \"\",\n branchPrefix:\n cliOptions.branchPrefix ||\n process.env.CPCG_BRANCH_PREFIX ||\n \"fix/cpcg-privacy\",\n baseBranch: cliOptions.baseBranch || process.env.CPCG_BASE_BRANCH || undefined,\n headless: parseBoolean(\n cliOptions.headless ?? process.env.CPCG_HEADLESS,\n true\n ),\n timeoutMs: cliOptions.timeoutMs\n ? Number(cliOptions.timeoutMs)\n : process.env.CPCG_TIMEOUT_MS\n ? Number(process.env.CPCG_TIMEOUT_MS)\n : 30000,\n };\n\n const parsed = GateConfigSchema.safeParse(merged);\n\n if (!parsed.success) {\n const errorDetails = parsed.error.issues\n .map((i) => ` - ${i.path.join(\".\")}: ${i.message}`)\n .join(\"\\n\");\n throw new Error(`Invalid Configuration:\\n${errorDetails}`);\n }\n\n return parsed.data;\n}\n","import { chromium, Browser, Page, Request } from \"playwright\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport {\n ChaosScenario,\n EvidenceRecord,\n GateConfig,\n LeakReport,\n RequestEvent,\n TrackerViolation,\n} from \"../../types/index.js\";\nimport { ChaosScannerInterface } from \"./types.js\";\nimport { identifyTracker } from \"./trackerDatabase.js\";\nimport {\n ACCEPT_SELECTORS,\n REJECT_SELECTORS,\n clickFirstMatching,\n} from \"./bannerLocators.js\";\n\n/**\n * True when `pageUrl` is still on the scanned target origin (or not yet navigated).\n * Used so tracker traffic from off-site navigation (e.g. a logo link to a vendor site)\n * is not attributed to the target under test.\n */\nexport function isOnTargetOrigin(pageUrl: string, targetOrigin: string): boolean {\n if (!pageUrl || pageUrl === \"about:blank\") return true;\n try {\n return new URL(pageUrl).origin === targetOrigin;\n } catch {\n return false;\n }\n}\n\n/**\n * Clicks the first anchor whose resolved URL stays on `targetOrigin`.\n * Off-site links (logo/footer/vendor) are skipped to avoid leaving the page under test.\n */\nexport async function clickFirstSameOriginLink(\n page: import(\"playwright\").Page,\n targetOrigin: string\n): Promise<boolean> {\n return page.evaluate((origin) => {\n const anchors = Array.from(document.querySelectorAll(\"a[href]\"));\n for (const a of anchors) {\n const href = a.getAttribute(\"href\");\n if (!href || href.startsWith(\"#\")) continue;\n try {\n const resolved = new URL(href, location.href);\n if (resolved.origin === origin) {\n (a as HTMLElement).click();\n return true;\n }\n } catch {\n // ignore invalid hrefs\n }\n }\n return false;\n }, targetOrigin);\n}\n\nexport class ChaosScanner implements ChaosScannerInterface {\n async scan(config: GateConfig): Promise<LeakReport> {\n const startTime = Date.now();\n const violations: TrackerViolation[] = [];\n const passedScenarios: ChaosScenario[] = [];\n const failedScenarios: ChaosScenario[] = [];\n const evidence: EvidenceRecord[] = [];\n const targetOrigin = new URL(config.targetUrl).origin;\n const want = (s: ChaosScenario): boolean => !config.scenarios?.length || config.scenarios.includes(s);\n\n let browser: Browser | null = null;\n\n try {\n // Pre-flight check: verify target URL is reachable\n try {\n const preflight = await fetch(config.targetUrl, { method: \"HEAD\", signal: AbortSignal.timeout(3000) });\n } catch (connErr) {\n // If HEAD fails, try GET once before concluding unreachable\n try {\n await fetch(config.targetUrl, { method: \"GET\", signal: AbortSignal.timeout(3000) });\n } catch {\n throw new Error(\n `Target URL is unreachable: ${config.targetUrl}. Please ensure your server or local fixture is running (e.g. 'pnpm run serve:fixture').`\n );\n }\n }\n\n browser = await chromium.launch({\n headless: config.headless,\n });\n\n // Scenario 1: Happy Path - Denied\n if (want(\"happy-path-denied\")) await this.runScenario(\n \"happy-path-denied\",\n browser,\n config,\n targetOrigin,\n async (page, _captured, ctx) => {\n ctx.log(\"goto\");\n await page.goto(config.targetUrl, { waitUntil: \"domcontentloaded\", timeout: config.timeoutMs });\n // Pre-Consent-Leak dokumentieren — Szenario trotzdem durchziehen.\n if (_captured.length > 0) {\n ctx.log(`pre-consent-leak-on-load(${_captured.length})`);\n }\n const denied = await clickFirstMatching(page, REJECT_SELECTORS, 2000);\n ctx.log(denied ? \"click:reject\" : \"click:reject-missing\");\n if (!denied) return \"not-checkable\";\n ctx.setPhase(\"post-reject\");\n ctx.log(\"phase:post-reject\");\n await page.waitForTimeout(500);\n return _captured.length === 0;\n },\n violations,\n passedScenarios,\n failedScenarios,\n evidence\n );\n\n // Scenario 2: Happy Path - Accepted (Pre-Consent Check)\n if (want(\"happy-path-accepted\")) await this.runScenario(\n \"happy-path-accepted\",\n browser,\n config,\n targetOrigin,\n async (page, _captured, ctx) => {\n ctx.log(\"goto\");\n await page.goto(config.targetUrl, { waitUntil: \"domcontentloaded\", timeout: config.timeoutMs });\n // Critical check: Did trackers fire BEFORE clicking Accept?\n if (_captured.length > 0) {\n ctx.log(`pre-consent-leak-on-load(${_captured.length})`);\n }\n const preConsentHits = _captured.length;\n const accepted = await clickFirstMatching(page, ACCEPT_SELECTORS, 2000);\n ctx.log(accepted ? \"click:accept\" : \"click:accept-missing\");\n // Ohne Accept-Klick wurde der Happy Path nicht ausgefuehrt — nie gruen.\n if (!accepted) return \"not-checkable\";\n // Intentional: post-accept tracker traffic is SUCCESS (re-activation), not a leak.\n // Phase SOFORT am Klick — Re-Activation im Settle-Fenster ist legal.\n ctx.setPhase(\"post-accept\");\n ctx.log(\"phase:post-accept\");\n // Wirkung nach dem Klick beobachten: erlaubtes Tracking darf/soll starten.\n await page.waitForTimeout(1200);\n await page.evaluate(() => {\n window.dispatchEvent(new Event(\"scroll\"));\n window.dispatchEvent(new Event(\"click\"));\n });\n await page.waitForTimeout(800);\n // Nur Pre-Consent-Funde vor dem Klick sind illegal — Re-Activation danach ist legal.\n return preConsentHits === 0;\n },\n violations,\n passedScenarios,\n failedScenarios,\n evidence\n );\n\n // Scenario 3: Chaos Path 1 - Fast-Click\n if (want(\"fast-click\")) await this.runScenario(\n \"fast-click\",\n browser,\n config,\n targetOrigin,\n async (page, _captured, ctx) => {\n ctx.log(\"goto:commit\");\n await page.goto(config.targetUrl, { waitUntil: \"commit\", timeout: config.timeoutMs });\n await page.waitForSelector(\"a[href]\", { timeout: 2000 }).catch(() => {});\n // Fast-click: immediately click a same-origin link before consent banner renders.\n // Off-site links (logo/footer/vendor) must not be followed — their trackers\n // would be misattributed to the target (see reports/realseiten-matrix.md).\n const clicked = await clickFirstSameOriginLink(page, targetOrigin);\n ctx.log(clicked ? \"click:same-origin-link\" : \"click:link-missing\");\n if (!clicked) return \"not-checkable\";\n await page.waitForTimeout(500);\n return _captured.length === 0;\n },\n violations,\n passedScenarios,\n failedScenarios,\n evidence\n );\n\n // Scenario 4: Chaos Path 2 - State Manipulation\n if (want(\"state-manipulation\")) await this.runScenario(\n \"state-manipulation\",\n browser,\n config,\n targetOrigin,\n async (page, _captured, ctx) => {\n ctx.log(\"goto\");\n await page.goto(config.targetUrl, { waitUntil: \"domcontentloaded\", timeout: config.timeoutMs });\n // Pre-Consent-Check dokumentieren, aber Storage-Wipe dennoch ausfuehren.\n await page.waitForTimeout(300);\n if (_captured.length > 0) {\n ctx.log(`pre-consent-leak-on-load(${_captured.length})`);\n }\n const preConsentHits = _captured.length;\n const accepted = await clickFirstMatching(page, ACCEPT_SELECTORS, 1500);\n ctx.log(accepted ? \"click:accept\" : \"click:accept-missing\");\n if (!accepted) return \"not-checkable\";\n // Phase SOFORT am Klick — Re-Activation im Settle-Fenster ist legal.\n ctx.setPhase(\"post-accept\");\n ctx.log(\"phase:post-accept\");\n await page.waitForTimeout(600);\n\n // Chaos: Wiping consent state during active session\n await page.evaluate(() => {\n localStorage.clear();\n sessionStorage.clear();\n });\n const context = page.context();\n await context.clearCookies();\n ctx.setPhase(\"post-wipe\");\n ctx.log(\"wipe:storage+cookies phase:post-wipe\");\n\n // Wirkung nach Wipe belegen: Reload + gezielte Events, nicht nur warten.\n await page.reload({ waitUntil: \"domcontentloaded\", timeout: config.timeoutMs });\n ctx.log(\"reload:post-wipe\");\n await page.waitForTimeout(400);\n await page.evaluate(() => {\n window.dispatchEvent(new Event(\"scroll\"));\n window.dispatchEvent(new Event(\"click\"));\n document.body?.dispatchEvent(new MouseEvent(\"click\", { bubbles: true }));\n });\n ctx.log(\"events:post-wipe\");\n await page.waitForTimeout(800);\n\n // illegal-Filter in runScenario bewertet Phasen (post-wipe etc.)\n return preConsentHits === 0;\n },\n violations,\n passedScenarios,\n failedScenarios,\n evidence\n );\n\n // Scenario 5: Chaos Path 3 - Network Drop (CMP Drop)\n if (want(\"network-drop\")) await this.runScenario(\n \"network-drop\",\n browser,\n config,\n targetOrigin,\n async (page, _captured, ctx) => {\n // Block CMP scripts — but never the target origin itself (e.g. /consent-policy).\n let cmpBlocked = false;\n await page.route(\n (url) => {\n const href = url.href;\n // Die Zielseite selbst und HTML-Dokumente (z. B. /consent-policy)\n // dürfen nie geblockt werden — CMP-Skripte dagegen schon,\n // auch wenn sie same-origin liegen (self-hosted Bundles).\n if (href === config.targetUrl) return false;\n if (/\\.html?([?#]|$)/i.test(href)) return false;\n return /consent|cookiebot|onetrust|klaro|usercentrics/i.test(href);\n },\n (route) => {\n cmpBlocked = true;\n return route.abort();\n }\n );\n\n ctx.log(\"goto:cmp-blocked\");\n await page.goto(config.targetUrl, { waitUntil: \"domcontentloaded\", timeout: config.timeoutMs });\n await page.waitForTimeout(600);\n\n // Kein blockierbares CMP-Skript → nicht prüfbar, nie bestanden.\n if (!cmpBlocked) {\n ctx.log(\"cmp-script-not-found\");\n return \"not-checkable\";\n }\n return _captured.length === 0;\n },\n violations,\n passedScenarios,\n failedScenarios,\n evidence\n );\n\n // Scenario 6: Widerruf — Accept, dann Widerrufen: stoppt Tracking? Rest-IDs?\n if (want(\"consent-revoked\")) await this.runRevocationScenario(\n browser,\n config,\n targetOrigin,\n violations,\n passedScenarios,\n failedScenarios,\n evidence\n );\n\n // Scenario 7: Nur Statistik erlaubt — Marketing muss ausbleiben\n if (want(\"category-selective\")) await this.runCategorySelectiveScenario(\n browser,\n config,\n targetOrigin,\n violations,\n passedScenarios,\n failedScenarios,\n evidence\n );\n\n // Scenario 8: Entscheidung merken — Reload, Unterseite, Neustart\n if (want(\"consent-persistence\")) await this.runPersistenceScenario(\n browser,\n config,\n targetOrigin,\n violations,\n passedScenarios,\n failedScenarios,\n evidence\n );\n\n // Scenario 9: Banner ignorieren — warten, scrollen, tippen: Tracking ohne Klick?\n if (want(\"banner-ignored\")) await this.runBannerIgnoredScenario(\n browser,\n config,\n targetOrigin,\n violations,\n passedScenarios,\n failedScenarios,\n evidence\n );\n\n // Scenario 10: Unterseiten & SPA-Navigation\n if (want(\"subpage-spa\")) await this.runSubpageSpaScenario(\n browser,\n config,\n targetOrigin,\n violations,\n passedScenarios,\n failedScenarios,\n evidence\n );\n\n // Scenario 11: CMP verzögert/fehlerhaft — Tracking-Zeitfenster?\n if (want(\"cmp-failure\")) await this.runCmpFailureScenario(\n browser,\n config,\n targetOrigin,\n violations,\n passedScenarios,\n failedScenarios,\n evidence\n );\n\n // Scenario 12: Eingebettete Inhalte — YouTube, Maps, Social vor Freigabe?\n if (want(\"embed-leaks\")) await this.runEmbedScenario(\n browser,\n config,\n targetOrigin,\n violations,\n passedScenarios,\n failedScenarios,\n evidence\n );\n\n // Consent Mode v2: Zustände vs. tatsächliche Google-Requests\n if (want(\"consent-mode-v2\")) await this.runConsentModeV2Scenario(\n browser,\n config,\n targetOrigin,\n violations,\n passedScenarios,\n failedScenarios,\n evidence\n );\n\n // Doppelte Events + First-Party-Heuristik\n if (want(\"duplicate-events\")) await this.runDuplicateEventsScenario(\n browser,\n config,\n targetOrigin,\n violations,\n passedScenarios,\n failedScenarios,\n evidence\n );\n\n // Mobile: sind Reject/Settings auf kleinen Displays bedienbar?\n if (want(\"mobile-usability\")) await this.runMobileUsabilityScenario(\n browser,\n config,\n targetOrigin,\n violations,\n passedScenarios,\n failedScenarios,\n evidence\n );\n } finally {\n if (browser) {\n await browser.close().catch(() => {});\n }\n }\n\n const durationMs = Date.now() - startTime;\n const allClean = violations.length === 0 && failedScenarios.length === 0;\n const naCount = evidence.filter((e) => e.status === \"not-applicable\").length;\n const summary = allClean\n ? `Clean: ${passedScenarios.length} scenario(s) passed${naCount ? `, ${naCount} not applicable` : \"\"} for ${config.targetUrl}. No privacy leaks detected.`\n : `Privacy issues: ${violations.length} tracker leak(s), ${failedScenarios.length} scenario(s) not clean.`;\n\n return {\n targetUrl: config.targetUrl,\n scannedAt: new Date().toISOString(),\n durationMs,\n totalViolations: violations.length,\n violations,\n passedScenarios,\n failedScenarios,\n summary,\n evidence,\n };\n }\n\n private async snapshotStorage(page: import(\"playwright\").Page): Promise<{\n cookies: string[];\n localStorageKeys: string[];\n sessionStorageKeys: string[];\n localStorageEntries?: { key: string; value: string }[];\n }> {\n const cookies = (await page.context().cookies().catch(() => [])).map((c) => `${c.name}@${c.domain}`);\n const local = await page\n .evaluate(() => Object.keys(localStorage))\n .catch(() => [] as string[]);\n const session = await page\n .evaluate(() => Object.keys(sessionStorage))\n .catch(() => [] as string[]);\n // Consent-relevante Werte mitlesen — ein blosser Schlüssel zeigt nicht erlaubt/abgelehnt.\n const localStorageEntries = await page\n .evaluate(() => {\n const out: { key: string; value: string }[] = [];\n const interesting = /consent|cookie|cpcg|optanon|usercentrics|didomi|category|purpose|analytics|marketing|statistic/i;\n for (const key of Object.keys(localStorage)) {\n if (!interesting.test(key)) continue;\n const v = localStorage.getItem(key) ?? \"\";\n out.push({ key, value: v.length > 120 ? v.slice(0, 120) + \"…\" : v });\n }\n return out;\n })\n .catch(() => [] as { key: string; value: string }[]);\n return {\n cookies,\n localStorageKeys: local,\n sessionStorageKeys: session,\n localStorageEntries: localStorageEntries.length ? localStorageEntries : undefined,\n };\n }\n\n /**\n * Fünf Kern-Chaos-Szenarien mit vollständigem Evidence-Record.\n * Phasen statt Capture-Wipe: Pre-Consent-Funde bleiben immer erhalten.\n * Ergebnis: passed nur bei ausgeführter Aktion und null Illegal-Funden.\n */\n private async runScenario(\n scenario: ChaosScenario,\n browser: Browser,\n _config: GateConfig,\n targetOrigin: string,\n runner: (\n page: import(\"playwright\").Page,\n captured: TrackerViolation[],\n ctx: {\n setPhase: (p: RequestEvent[\"phase\"]) => void;\n log: (action: string) => void;\n }\n ) => Promise<boolean | \"not-checkable\">,\n violations: TrackerViolation[],\n passedScenarios: ChaosScenario[],\n failedScenarios: ChaosScenario[],\n evidence: EvidenceRecord[]\n ): Promise<void> {\n const context = await browser.newContext();\n const page = await context.newPage();\n const scenarioViolations: TrackerViolation[] = [];\n const timeline: RequestEvent[] = [];\n const actionSequence: string[] = [];\n const phaseById = new Map<string, RequestEvent[\"phase\"]>();\n let phase: RequestEvent[\"phase\"] = \"pre-consent\";\n\n // Setup network request interception\n page.on(\"request\", (req: Request) => {\n // Only attribute tracker traffic observed while the page is still on the target.\n // After off-site navigation, third-party trackers belong to the other site.\n const frameUrl = req.frame()?.url() || page.url();\n if (!isOnTargetOrigin(frameUrl, targetOrigin)) {\n return;\n }\n const url = req.url();\n const tracker = identifyTracker(url);\n timeline.push({\n at: new Date().toISOString(),\n url,\n trackerName: tracker?.name,\n trackerCategory: tracker?.category,\n phase,\n });\n if (tracker) {\n const ruleId =\n phase === \"post-wipe\"\n ? \"tracking-without-consent\"\n : phase === \"post-reject\" || phase === \"post-reject-restart\"\n ? \"tracking-after-deny\"\n : phase === \"post-revoke\"\n ? \"tracking-after-revoke\"\n : \"pre-consent-tracking\";\n const violation: TrackerViolation = {\n id: `${scenario}-${Date.now()}-${Math.random().toString(36).substring(2, 6)}`,\n ruleId,\n scenario,\n trackerName: tracker.name,\n trackerCategory: tracker.category,\n requestUrl: url,\n method: req.method(),\n timestamp: new Date().toISOString(),\n description: `Unauthorized ${tracker.name} (${tracker.category}) request triggered during scenario '${scenario}'.`,\n };\n scenarioViolations.push(violation);\n phaseById.set(violation.id, phase);\n }\n });\n\n const storageBefore = await this.snapshotStorage(page);\n let outcome: boolean | \"not-checkable\" = false;\n try {\n outcome = await runner(page, scenarioViolations, {\n setPhase: (p) => {\n phase = p;\n },\n log: (a) => actionSequence.push(a),\n });\n } catch (err) {\n outcome = false;\n actionSequence.push(`error:${String(err).slice(0, 80)}`);\n }\n const storageAfter = await this.snapshotStorage(page).catch(() => storageBefore);\n await context.close().catch(() => {});\n\n // Illegal = Pre-Consent-, Post-Wipe- und Post-Reject/Revoke-Funde. Post-accept ist Re-Activation (legal).\n const illegal = scenarioViolations.filter((v) => {\n const p = phaseById.get(v.id) ?? \"pre-consent\";\n // post-selection ist die Kategorieentscheidung selbst — kein per-se Verstoss.\n return p === \"pre-consent\" || p === \"post-wipe\" || p === \"post-revoke\" || p === \"post-reject\" || p === \"post-reject-restart\";\n });\n const postAccept = scenarioViolations.length - illegal.length;\n\n let status: EvidenceRecord[\"status\"];\n if (outcome === \"not-checkable\") {\n // Szenario selbst nicht prüfbar — illegale Funde aus dem Versuch bleiben dokumentiert.\n status = \"not-checkable\";\n failedScenarios.push(scenario);\n violations.push(...illegal);\n } else if (illegal.length > 0 || outcome === false) {\n status = \"suspicious\";\n failedScenarios.push(scenario);\n violations.push(...illegal);\n } else {\n status = \"passed\";\n passedScenarios.push(scenario);\n }\n\n const note =\n illegal.length > 0\n ? actionSequence.some((a) => a.startsWith(\"pre-consent-leak-on-load\"))\n ? `Pre-Consent-Leak bereits beim Seitenaufruf (${illegal.filter((v) => (phaseById.get(v.id) ?? \"\") === \"pre-consent\").length} Request(s)). Szenario wurde trotzdem ausgeführt und vollständig dokumentiert.`\n : `${illegal.length} Tracker-Request(s) in unzulässiger Phase (pre-consent/post-reject/post-wipe/post-revoke).`\n : status === \"passed\"\n ? `Aktion ausgeführt, keine Tracker-Requests vor der Zustimmung.${postAccept ? ` ${postAccept} post-accept Request(s) (Re-Activation, legal).` : \"\"}`\n : status === \"not-checkable\"\n ? \"Szenario nicht prüfbar — erforderliche Aktion (Button/Link) nicht ausführbar (kein grünes Häkchen).\"\n : \"Szenario ohne sauberen Nachweis abgeschlossen.\";\n\n evidence.push({\n scenario,\n status,\n note,\n actionSequence,\n requestTimeline: timeline,\n storageBefore,\n storageAfter,\n targetUrl: _config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n }\n\n private async snap(\n page: import(\"playwright\").Page,\n scenario: string,\n label: string,\n shots: { label: string; path: string; at: string }[],\n acts: { at: string; action: string }[],\n actionSequence: string[]\n ): Promise<void> {\n const dir = path.resolve(\"reports/evidence\");\n await fs.mkdir(dir, { recursive: true });\n const at = new Date().toISOString();\n const file = path.join(dir, `${scenario}-${label}-${Date.now()}.png`);\n await page.screenshot({ path: file, fullPage: true }).catch(() => {});\n shots.push({ label, path: file, at });\n actionSequence.push(`screenshot:${label}`);\n acts.push({ at, action: `screenshot:${label}` });\n }\n\n private logAct(\n acts: { at: string; action: string }[],\n actionSequence: string[],\n action: string\n ): void {\n const at = new Date().toISOString();\n actionSequence.push(action);\n acts.push({ at, action });\n }\n\n /**\n * Widerruf: erst akzeptieren, dann widerrufen. Prüft (a) keine neuen Tracker-Requests\n * nach Widerruf, (b) ob Tracking-IDs in Cookies/Storage zurückbleiben.\n * Kein Widerruf-Button — status «not-checkable» (nie grün).\n */\n /**\n * Kategorien-Granularität: Statistik erlaubt, Marketing abgelehnt.\n * Marketing-Tracker (Meta, TikTok, LinkedIn, Criteo ⬦) dürfen danach NICHT feuern.\n * Keine Kategorie-UI — status «not-checkable».\n */\n private async runCategorySelectiveScenario(\n browser: Browser,\n config: GateConfig,\n targetOrigin: string,\n violations: TrackerViolation[],\n passedScenarios: ChaosScenario[],\n failedScenarios: ChaosScenario[],\n evidence: EvidenceRecord[]\n ): Promise<void> {\n const context = await browser.newContext();\n const page = await context.newPage();\n const timeline: RequestEvent[] = [];\n const actionSequence: string[] = [];\n let phase: RequestEvent[\"phase\"] = \"pre-consent\";\n\n page.on(\"request\", (req) => {\n const frameUrl = req.frame()?.url() || page.url();\n if (!isOnTargetOrigin(frameUrl, targetOrigin)) return;\n const hit = identifyTracker(req.url());\n timeline.push({ at: new Date().toISOString(), url: req.url(), trackerName: hit?.name, trackerCategory: hit?.category, phase });\n // Nur Marketing nach Kategorieentscheidung ist ein Verstoss — erlaubtes Analytics (post-selection) nicht.\n if (hit && phase === \"post-selection\" && hit.category === \"marketing\") {\n violations.push({\n id: `category-selective-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,\n ruleId: \"tracking-declined-category\",\n scenario: \"category-selective\",\n trackerName: hit.name,\n trackerCategory: hit.category,\n requestUrl: req.url(),\n method: req.method(),\n timestamp: new Date().toISOString(),\n description: `${hit.name} feuert, obwohl Marketing-Kategorie abgelehnt wurde.`,\n });\n }\n });\n\n try {\n await page.goto(config.targetUrl, { waitUntil: \"domcontentloaded\", timeout: config.timeoutMs });\n actionSequence.push(\"goto\");\n const storageBefore = await this.snapshotStorage(page);\n\n // Kategorie-Panel öffnen, dann Marketing aus / Statistik an\n await clickFirstMatching(page, [\"#btn-settings\", \"button[data-action='settings']\", \".open-prefs\"], 1200);\n actionSequence.push(\"click:settings\");\n await page.waitForTimeout(200);\n\n const marketingOff = await page\n .evaluate(() => {\n const boxes = Array.from(\n document.querySelectorAll<HTMLInputElement>('input[type=\"checkbox\"]')\n );\n let touched = 0;\n for (const box of boxes) {\n const label = (\n box.id +\n \" \" +\n box.name +\n \" \" +\n (box.closest(\"label\")?.textContent || \"\") +\n \" \" +\n (box.getAttribute(\"aria-label\") || \"\")\n ).toLowerCase();\n if (/marketing|advertising|werbung|ads/.test(label)) {\n if (box.checked) box.click();\n touched++;\n }\n if (/statistic|analytics|statistik|messung/.test(label)) {\n if (!box.checked) box.click();\n touched++;\n }\n }\n return touched;\n })\n .catch(() => 0);\n\n if (marketingOff === 0) {\n // Keine Kategorie-Checkboxen — nicht prüfbar\n const storageAfter = await this.snapshotStorage(page);\n evidence.push({\n scenario: \"category-selective\",\n status: \"not-checkable\",\n note: \"Keine Kategorie-Auswahl (Statistik/Marketing) im Banner gefunden — nicht prüfbar.\",\n actionSequence,\n requestTimeline: timeline,\n storageBefore,\n storageAfter,\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n failedScenarios.push(\"category-selective\");\n return;\n }\n // Phase VOR dem Save-Klick: Kategorieentscheidung, nicht Reject/Accept.\n // Erlaubtes Analytics danach ist legal und darf nicht als Ablehnungs-Verstoss erscheinen.\n phase = \"post-selection\";\n actionSequence.push(`categories:marketing-off(${marketingOff})`);\n\n const saved =\n (await clickFirstMatching(page, [\"#btn-save\", \"button[data-action='save']\", \".save-settings\"], 1500)) ||\n (await clickFirstMatching(page, ACCEPT_SELECTORS, 1500));\n actionSequence.push(saved ? \"click:save-choices\" : \"click:save-missing\");\n if (!saved) {\n // Ohne gespeicherte Auswahl wurde die Kategorie-Entscheidung nie angewandt.\n const storageAfterNoSave = await this.snapshotStorage(page);\n evidence.push({\n scenario: \"category-selective\",\n status: \"not-checkable\",\n note: \"Kategorie-Auswahl konnte nicht gespeichert werden — kein Save/Accept-Button (kein grünes Häkchen).\",\n actionSequence,\n requestTimeline: timeline,\n storageBefore,\n storageAfter: storageAfterNoSave,\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n failedScenarios.push(\"category-selective\");\n return;\n }\n // Judge tracking from the moment choices are saved (user decision point).\n await page.waitForTimeout(1800);\n\n const storageAfter = await this.snapshotStorage(page);\n const decisionPhase = \"post-selection\";\n const marketingLeaks = timeline.filter(\n (e) => e.phase === decisionPhase && e.trackerName && e.trackerCategory === \"marketing\"\n );\n const preConsentLeaks = timeline.filter(\n (e) => e.phase === \"pre-consent\" && e.trackerName\n );\n const analyticsOk = timeline.filter(\n (e) => e.phase === decisionPhase && e.trackerName && e.trackerCategory === \"analytics\"\n );\n const catValues = (storageAfter.localStorageEntries ?? [])\n .filter((e) => /analytics|marketing|consent|category/i.test(e.key))\n .map((e) => `${e.key}=${e.value}`)\n .join(\", \");\n const decisionRequests = timeline.filter((e) => e.phase === \"post-selection\" && e.trackerName);\n const status: EvidenceRecord[\"status\"] = marketingLeaks.length > 0 ? \"suspicious\" : \"passed\";\n\n evidence.push({\n scenario: \"category-selective\",\n status,\n note:\n status === \"passed\"\n ? [\n preConsentLeaks.length > 0\n ? `Kategorie-Auswahl bestanden (keine Marketing-Tracker nach «nur Statistik»); zusätzlich ${preConsentLeaks.length} Pre-Consent-Request(s) vor der Auswahl dokumentiert.`\n : \"Nach «nur Statistik» keine Marketing-Tracker-Requests beobachtet.\",\n analyticsOk.length > 0\n ? `Erlaubtes Analytics-Tracking nach Freigabe belegt (${analyticsOk.length} Request(s), Phase post-selection).`\n : \"Erlaubtes Analytics-Tracking nach Freigabe nicht beobachtet.\",\n catValues ? `Gespeicherte Kategorien: ${catValues}.` : \"\",\n `Prüfumfang: Klick auf «Auswahl speichern» (Marketing aus, Statistik an), danach 1,8 s Beobachtungsfenster mit ${decisionRequests.length} Tracker-Request(s) in Phase post-selection. Interaktionen: Settings öffnen, Checkboxen setzen, Speichern.`,\n ]\n .filter(Boolean)\n .join(\" \")\n : `${marketingLeaks.length} Marketing-Tracker trotz abgelehnter Kategorie aktiv.`,\n actionSequence,\n requestTimeline: timeline,\n storageBefore,\n storageAfter,\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n\n if (status === \"passed\") passedScenarios.push(\"category-selective\");\n else failedScenarios.push(\"category-selective\");\n } catch (err) {\n evidence.push({\n scenario: \"category-selective\" as never,\n status: \"not-checkable\",\n note: `Szenario mit Fehler abgebrochen: ${String(err).slice(0, 120)}`,\n actionSequence: [],\n requestTimeline: [],\n storageBefore: { cookies: [], localStorageKeys: [], sessionStorageKeys: [] },\n storageAfter: { cookies: [], localStorageKeys: [], sessionStorageKeys: [] },\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n failedScenarios.push(\"category-selective\");\n } finally {\n await context.close().catch(() => {});\n }\n }\n\n /**\n * Entscheidung merken: nach «Ablehnen» Reload, Unterseiten-URL und Browser-Neustart\n * (storageState). Tracker müssen ausbleiben, die Entscheidung muss erhalten bleiben.\n */\n private async runPersistenceScenario(\n browser: Browser,\n config: GateConfig,\n targetOrigin: string,\n violations: TrackerViolation[],\n passedScenarios: ChaosScenario[],\n failedScenarios: ChaosScenario[],\n evidence: EvidenceRecord[]\n ): Promise<void> {\n const context = await browser.newContext();\n const page = await context.newPage();\n const timeline: RequestEvent[] = [];\n const actionSequence: string[] = [];\n let phase: RequestEvent[\"phase\"] = \"pre-consent\";\n let denied = false;\n\n const onReq = (req: import(\"playwright\").Request) => {\n const frameUrl = req.frame()?.url() || page.url();\n if (!isOnTargetOrigin(frameUrl, targetOrigin)) return;\n const hit = identifyTracker(req.url());\n timeline.push({ at: new Date().toISOString(), url: req.url(), trackerName: hit?.name, trackerCategory: hit?.category, phase });\n // Nur bei echter Ablehnung sind Tracker-Requests ein Verstoss.\n if (hit && denied && (phase === \"post-reject\" || phase === \"post-reject-restart\")) {\n violations.push({\n id: `consent-persistence-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,\n ruleId: \"tracking-after-deny\",\n scenario: \"consent-persistence\",\n trackerName: hit.name,\n trackerCategory: hit.category,\n requestUrl: req.url(),\n method: req.method(),\n timestamp: new Date().toISOString(),\n description: `${hit.name} feuert, obwohl Ablehnung gespeichert sein sollte.`,\n });\n }\n };\n page.on(\"request\", onReq);\n\n try {\n await page.goto(config.targetUrl, { waitUntil: \"domcontentloaded\", timeout: config.timeoutMs });\n actionSequence.push(\"goto\");\n const storageBefore = await this.snapshotStorage(page);\n\n denied = await clickFirstMatching(page, REJECT_SELECTORS, 2500);\n actionSequence.push(denied ? \"click:reject\" : \"click:reject-missing\");\n\n if (!denied) {\n // Kein Ablehnen-Button — Persistenz nicht prüfbar (nie grün).\n const storageAfter = await this.snapshotStorage(page);\n evidence.push({\n scenario: \"consent-persistence\",\n status: \"not-checkable\",\n note: \"Kein Ablehnen-Button — Persistenz der Entscheidung nicht prüfbar.\",\n actionSequence,\n requestTimeline: timeline,\n storageBefore,\n storageAfter,\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n failedScenarios.push(\"consent-persistence\");\n return;\n }\n await page.waitForTimeout(600);\n\n const consentStillSet = await page\n .evaluate(() => {\n const keys = [\"cpcg_consent\", \"OptanonConsent\", \"CookieConsent\", \"usercentrics-consent\", \"consent\"];\n const ls = keys.filter((k) => {\n const v = localStorage.getItem(k);\n return v && v !== \"accepted\";\n }).length;\n // CMPs speichern Consent klassisch in Cookies (z. B. OptanonConsent)\n const cookieKeys = /OptanonConsent|CookieConsent|usercentrics|consent/i;\n const ck = document.cookie\n .split(\";\")\n .map((c) => c.trim().split(\"=\")[0])\n .filter((name) => cookieKeys.test(name)).length;\n return ls + ck;\n })\n .catch(() => 0);\n\n // (a) Reload — nach gespeicherter Ablehnung, nicht post-accept\n phase = \"post-reject\";\n await page.reload({ waitUntil: \"domcontentloaded\", timeout: config.timeoutMs });\n actionSequence.push(\"reload\");\n await page.waitForTimeout(500);\n\n // (b) Unterseite gleiche Origin\n await page.goto(`${targetOrigin}/subpage-persistence-check`, {\n waitUntil: \"domcontentloaded\",\n timeout: config.timeoutMs,\n }).catch(() => {});\n actionSequence.push(\"goto:subpage\");\n await page.waitForTimeout(400);\n\n // (c) «Browser-Neustart» mit storageState\n const storageAtRestart = await this.snapshotStorage(page);\n const state = await context.storageState();\n await context.close();\n const ctx2 = await browser.newContext({ storageState: state });\n const page2 = await ctx2.newPage();\n page2.on(\"request\", (req) => {\n const frameUrl = req.frame()?.url() || page2.url();\n if (!isOnTargetOrigin(frameUrl, targetOrigin)) return;\n const hit = identifyTracker(req.url());\n timeline.push({\n at: new Date().toISOString(),\n url: req.url(),\n trackerName: hit?.name,\n trackerCategory: hit?.category,\n phase: \"post-reject-restart\",\n });\n // Restart-Bein bewerten: Tracker nach Ablehnung + Neustart = Verstoss\n if (hit && denied) {\n violations.push({\n id: `consent-persistence-restart-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,\n ruleId: \"tracking-after-deny\",\n scenario: \"consent-persistence\",\n trackerName: hit.name,\n trackerCategory: hit.category,\n requestUrl: req.url(),\n method: req.method(),\n timestamp: new Date().toISOString(),\n description: `${hit.name} feuert nach Ablehnung und Browser-Neustart.`,\n });\n }\n });\n await page2.goto(config.targetUrl, { waitUntil: \"domcontentloaded\", timeout: config.timeoutMs });\n actionSequence.push(\"restart:storageState\");\n await page2.waitForTimeout(800);\n await ctx2.close();\n\n const storageAfter = await this.snapshotStorage(page2).catch(() => storageAtRestart);\n const leaks = timeline.filter((e) => e.trackerName && (e.phase === \"post-reject\" || e.phase === \"post-reject-restart\"));\n const deniedPersists = consentStillSet > 0;\n // Explizite Ableitung: Leak → suspicious; kein erkennbarer Consent-Marker → nicht prüfbar; sonst passed\n const status: EvidenceRecord[\"status\"] =\n leaks.length > 0 ? \"suspicious\" : !deniedPersists ? \"not-checkable\" : \"passed\";\n\n evidence.push({\n scenario: \"consent-persistence\",\n status,\n note:\n status === \"passed\"\n ? \"Ablehnung überlebt Reload, Unterseite und Neustart; kein Tracking ohne erneute Zustimmung.\"\n : status === \"suspicious\"\n ? `${leaks.length} Tracker-Request(s) trotz gespeicherter Ablehnung.`\n : \"Keine konsistente Entscheidung im Storage gefunden — nicht prüfbar.\",\n actionSequence,\n requestTimeline: timeline,\n storageBefore,\n storageAfter,\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n\n if (status === \"passed\") passedScenarios.push(\"consent-persistence\");\n else failedScenarios.push(\"consent-persistence\");\n } catch (err) {\n evidence.push({\n scenario: \"consent-persistence\" as never,\n status: \"not-checkable\",\n note: `Szenario mit Fehler abgebrochen: ${String(err).slice(0, 120)}`,\n actionSequence: [],\n requestTimeline: [],\n storageBefore: { cookies: [], localStorageKeys: [], sessionStorageKeys: [] },\n storageAfter: { cookies: [], localStorageKeys: [], sessionStorageKeys: [] },\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n failedScenarios.push(\"consent-persistence\");\n } finally {\n await context.close().catch(() => {});\n }\n }\n\n /**\n * Banner ignorieren: kein Klick, nur warten, scrollen, Navigation.\n * Tracker dürfen nicht über Timer/Scroll/Input allein starten.\n */\n /**\n * Unterseiten & SPA: Direkteinstieg auf Subpage, dann Client-Navigation ohne Reload.\n * Consent-Schutz muss auch dort greifen.\n */\n /**\n * CMP langsam oder defekt: CMP-Skripte verzögern/abbringen, dann beobachten,\n * ob im Zeitfenster Tracker starten (Default-State-Leak).\n */\n /**\n * Eingebettete Inhalte (YouTube, Maps, Social, Chat): Drittanbieter-Requests\n * vor Consent-Freigabe des Embeds. Inklusive iframe-src und nachgeladenen SDKs.\n */\n /**\n * Consent Mode v2: dataLayer-Konsens-Zustände (ad_storage, analytics_storage, ⬦)\n * gegen tatsächliche Google-Requests und Cookies trennen.\n * Bei Basic dürfen nach Ablehnung keine Nutzungsdaten laufen; bei Advanced\n * sind cookielose Pings möglich — beides wird getrennt ausgewiesen.\n */\n /**\n * Doppelte Events: ein Seitenaufruf nach Consent darf page_view nicht doppelt zählen\n * (Plugin + GTM parallel). First-Party-Heuristik: verdächtige same-origin Endpunkte\n * (collect, pixel, track) werden markiert — Server-zu-Server ist von aussen begrenzt beweisbar.\n */\n /**\n * Mobile: iPhone-Viewport. Reject und Settings müssen sichtbar und klickbar sein.\n * Nur Accept bedienbar — suspicious (Dark Pattern); keine Buttons — not-checkable.\n */\n private async runMobileUsabilityScenario(\n browser: Browser,\n config: GateConfig,\n targetOrigin: string,\n _violations: TrackerViolation[],\n passedScenarios: ChaosScenario[],\n failedScenarios: ChaosScenario[],\n evidence: EvidenceRecord[]\n ): Promise<void> {\n const context = await browser.newContext({\n viewport: { width: 390, height: 844 },\n isMobile: true,\n hasTouch: true,\n userAgent:\n \"Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1\",\n });\n const page = await context.newPage();\n const actionSequence: string[] = [];\n const actionTimeline: { at: string; action: string }[] = [];\n const screenshots: { label: string; path: string; at: string }[] = [];\n const timeline: RequestEvent[] = [];\n\n try {\n await page.goto(config.targetUrl, { waitUntil: \"domcontentloaded\", timeout: config.timeoutMs });\n this.logAct(actionTimeline, actionSequence, \"goto:mobile-390x844\");\n const storageBefore = await this.snapshotStorage(page);\n await this.snap(page, \"mobile-usability\", \"01-mobile-banner\", screenshots, actionTimeline, actionSequence);\n\n type ProbeResult = {\n found: boolean;\n selector: string;\n visible: boolean;\n touchOk: boolean;\n width: number;\n height: number;\n };\n const probe = async (selectors: string[]): Promise<ProbeResult> => {\n for (const sel of selectors) {\n const loc = page.locator(sel).first();\n const visible = await loc.isVisible({ timeout: 400 }).catch(() => false);\n if (visible) {\n const box = await loc.boundingBox().catch(() => null);\n const w = Math.round(box?.width ?? 0);\n const h = Math.round(box?.height ?? 0);\n return { found: true, selector: sel, visible: true, touchOk: w >= 24 && h >= 24, width: w, height: h };\n }\n }\n return { found: false, selector: \"\", visible: false, touchOk: false, width: 0, height: 0 };\n };\n\n const accept = await probe(ACCEPT_SELECTORS);\n const reject = await probe(REJECT_SELECTORS);\n\n // Sichtbarkeit, Bedienbarkeit (Touch-Target) und Klickergebnis getrennt erfassen\n const describe = (p: ProbeResult) =>\n `${p.found ? \"gefunden\" : \"fehlt\"} sichtbar=${p.visible ? \"ja\" : \"nein\"} ${p.width}x${p.height}px touch=${p.touchOk ? \"ok\" : \"zu-klein\"}`;\n this.logAct(actionTimeline, actionSequence, `probe:accept ${describe(accept)}`);\n this.logAct(actionTimeline, actionSequence, `probe:reject ${describe(reject)}`);\n\n let rejectTapOk = false;\n if (reject.found) {\n const loc = page.locator(reject.selector).first();\n rejectTapOk = await loc\n .tap({ timeout: 2000 })\n .then(() => true)\n .catch(() => loc.click({ timeout: 2000 }).then(() => true).catch(() => false));\n this.logAct(actionTimeline, actionSequence, `tap:reject=${rejectTapOk ? \"ok\" : \"failed\"}`);\n }\n await page.waitForTimeout(400);\n const storageAfter = await this.snapshotStorage(page);\n\n const acceptUsable = accept.found && accept.visible && accept.touchOk;\n const rejectUsable = reject.found && reject.visible && reject.touchOk;\n // Nur bei eindeutigem Nachweis werten: Dark Pattern nur, wenn Accept bedienbar\n // und Reject gefunden, aber nicht bedienbar. Alles andere: nicht prüfbar.\n const status: EvidenceRecord[\"status\"] =\n !accept.found && !reject.found\n ? \"not-checkable\"\n : acceptUsable && rejectUsable && rejectTapOk\n ? \"passed\"\n : acceptUsable && reject.found && !rejectUsable\n ? \"suspicious\"\n : \"not-checkable\";\n\n const probeSummary = `Accept: ${describe(accept)} · Reject: ${describe(reject)} · Tap-Reject: ${rejectTapOk ? \"ok\" : \"failed/keiner\"}`;\n evidence.push({\n scenario: \"mobile-usability\",\n status,\n note:\n status === \"passed\"\n ? `Accept und Reject im Mobile-Viewport bedienbar. ${probeSummary}`\n : status === \"suspicious\"\n ? `Nur «Akzeptieren» ist bedienbar, «Ablehnen» nicht (Dark-Pattern-Verdacht). ${probeSummary}`\n : `Ohne eindeutigen Nachweis nicht prüfbar. ${probeSummary}`,\n actionSequence,\n actionTimeline,\n requestTimeline: timeline,\n storageBefore,\n storageAfter,\n screenshots,\n screenshotPath: screenshots[0]?.path,\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n\n if (status === \"passed\") passedScenarios.push(\"mobile-usability\");\n else failedScenarios.push(\"mobile-usability\");\n } catch (err) {\n evidence.push({\n scenario: \"mobile-usability\" as never,\n status: \"not-checkable\",\n note: `Szenario mit Fehler abgebrochen: ${String(err).slice(0, 120)}`,\n actionSequence: [],\n requestTimeline: [],\n storageBefore: { cookies: [], localStorageKeys: [], sessionStorageKeys: [] },\n storageAfter: { cookies: [], localStorageKeys: [], sessionStorageKeys: [] },\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n failedScenarios.push(\"mobile-usability\");\n await context.close().catch(() => {});\n } finally {\n await context.close().catch(() => {});\n }\n }\n\n private async runDuplicateEventsScenario(\n browser: Browser,\n config: GateConfig,\n targetOrigin: string,\n violations: TrackerViolation[],\n passedScenarios: ChaosScenario[],\n failedScenarios: ChaosScenario[],\n evidence: EvidenceRecord[]\n ): Promise<void> {\n const context = await browser.newContext();\n const page = await context.newPage();\n const timeline: RequestEvent[] = [];\n const actionSequence: string[] = [];\n const actionTimeline: { at: string; action: string }[] = [];\n const screenshots: { label: string; path: string; at: string }[] = [];\n const pageviews: string[] = [];\n const firstPartySuspicious: string[] = [];\n let phase: RequestEvent[\"phase\"] = \"pre-consent\";\n\n page.on(\"request\", (req) => {\n const url = req.url();\n const hit = identifyTracker(url);\n timeline.push({ at: new Date().toISOString(), url, trackerName: hit?.name, phase: \"post-accept\" });\n if (/\\/(collect|pixel|track|beacon|analytics\\.php)/i.test(url) && /page_view|pageview|en=page/i.test(url)) {\n pageviews.push(url);\n }\n // First-Party-Heuristik: same-origin, aber Tracking-Pfade\n try {\n if (url.startsWith(targetOrigin) && /\\/(collect|pixel|track|beacon|_stm|_paq)/i.test(url)) {\n firstPartySuspicious.push(url);\n }\n } catch {\n /* ignore */\n }\n });\n\n try {\n await page.goto(config.targetUrl, { waitUntil: \"domcontentloaded\", timeout: config.timeoutMs });\n this.logAct(actionTimeline, actionSequence, \"goto\");\n const storageBefore = await this.snapshotStorage(page);\n const accepted = await clickFirstMatching(page, ACCEPT_SELECTORS, 2000);\n this.logAct(actionTimeline, actionSequence, accepted ? \"click:accept\" : \"click:accept-missing\");\n phase = \"post-accept\";\n await page.waitForTimeout(800);\n // frischer Seitenaufruf nach Consent — Zähler zurücksetzen\n pageviews.length = 0;\n firstPartySuspicious.length = 0;\n await page.reload({ waitUntil: \"domcontentloaded\", timeout: config.timeoutMs });\n this.logAct(actionTimeline, actionSequence, \"reload:after-consent\");\n await page.waitForTimeout(1500);\n await this.snap(page, \"duplicate-events\", \"01-after-reload\", screenshots, actionTimeline, actionSequence);\n\n const storageAfter = await this.snapshotStorage(page);\n const duplicates = pageviews.length > 1;\n // Kein Subjekt (keine Beacons) = nicht prüfbar, nie grün.\n const status: EvidenceRecord[\"status\"] =\n pageviews.length === 0 ? \"not-checkable\" : duplicates ? \"suspicious\" : \"passed\";\n\n evidence.push({\n scenario: \"duplicate-events\",\n status,\n note: [\n `page_view-Beacons nach Consent-Reload: ${pageviews.length}`,\n pageviews.length === 0\n ? \"Keine page_view-Beacons erfasst — Szenario nicht prüfbar (keine Analytics-Installation sichtbar).\"\n : duplicates\n ? \"Doppelte Events möglich (Plugin + GTM parallel).\"\n : \"Keine doppelten page_view-Events beobachtet.\",\n firstPartySuspicious.length\n ? `First-Party-Verdacht: ${firstPartySuspicious.length} same-origin Tracking-Pfad(e) — Server-zu-Server nur begrenzt beweisbar.`\n : \"Keine verdächtigen First-Party-Tracking-Pfade.\",\n ].join(\" · \"),\n actionSequence,\n actionTimeline,\n requestTimeline: timeline,\n storageBefore,\n storageAfter,\n screenshots,\n screenshotPath: screenshots[0]?.path,\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n\n if (status === \"passed\") {\n passedScenarios.push(\"duplicate-events\");\n } else if (status === \"suspicious\") {\n // Violation nur bei echtem Befund — not-checkable ist kein Leak\n failedScenarios.push(\"duplicate-events\");\n violations.push({\n id: `duplicate-events-${Date.now()}`,\n ruleId: \"duplicate-events\",\n scenario: \"duplicate-events\",\n trackerName: \"Analytics page_view\",\n trackerCategory: \"analytics\",\n requestUrl: pageviews[0] || config.targetUrl,\n method: \"GET\",\n timestamp: new Date().toISOString(),\n description: `Mehrere page_view-Beacons pro Aufruf (${pageviews.length}).`,\n });\n } else {\n failedScenarios.push(\"duplicate-events\");\n }\n } catch (err) {\n evidence.push({\n scenario: \"duplicate-events\" as never,\n status: \"not-checkable\",\n note: `Szenario mit Fehler abgebrochen: ${String(err).slice(0, 120)}`,\n actionSequence: [],\n requestTimeline: [],\n storageBefore: { cookies: [], localStorageKeys: [], sessionStorageKeys: [] },\n storageAfter: { cookies: [], localStorageKeys: [], sessionStorageKeys: [] },\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n failedScenarios.push(\"duplicate-events\");\n } finally {\n await context.close().catch(() => {});\n }\n }\n\n private async runConsentModeV2Scenario(\n browser: Browser,\n config: GateConfig,\n targetOrigin: string,\n violations: TrackerViolation[],\n passedScenarios: ChaosScenario[],\n failedScenarios: ChaosScenario[],\n evidence: EvidenceRecord[]\n ): Promise<void> {\n const context = await browser.newContext();\n const page = await context.newPage();\n const timeline: RequestEvent[] = [];\n const actionSequence: string[] = [];\n const actionTimeline: { at: string; action: string }[] = [];\n const screenshots: { label: string; path: string; at: string }[] = [];\n\n const googleRequests: string[] = [];\n let phase: RequestEvent[\"phase\"] = \"pre-consent\";\n page.on(\"request\", (req) => {\n const url = req.url();\n const isGoogle = /google-analytics\\.com|googletagmanager\\.com|doubleclick\\.net|googleadservices\\.com/i.test(url);\n timeline.push({ at: new Date().toISOString(), url, trackerName: identifyTracker(url)?.name, trackerCategory: identifyTracker(url)?.category, phase });\n if (isGoogle) googleRequests.push(url);\n });\n\n const readConsent = async (): Promise<Record<string, string>> => {\n return page\n .evaluate(() => {\n const out: Record<string, string> = {};\n try {\n const dl = (window as any).dataLayer as unknown[] | undefined;\n if (Array.isArray(dl)) {\n for (const entry of dl) {\n const arr = entry as any; if (arr && arr[0] === \"consent\" && (arr[1] === \"default\" || arr[1] === \"update\")) {\n const v = arr[2] as Record<string, string>;\n if (v && typeof v === \"object\") {\n for (const k of [\"ad_storage\", \"analytics_storage\", \"ad_user_data\", \"ad_personalization\"] as const) {\n if (v[k]) out[k] = v[k];\n }\n }\n }\n }\n }\n } catch {\n /* ignore */\n }\n return out;\n })\n .catch(() => ({} as Record<string, string>));\n };\n\n try {\n await page.goto(config.targetUrl, { waitUntil: \"domcontentloaded\", timeout: config.timeoutMs });\n this.logAct(actionTimeline, actionSequence, \"goto\");\n const storageBefore = await this.snapshotStorage(page);\n const defaults = await readConsent();\n this.logAct(actionTimeline, actionSequence, `consent:default(${Object.keys(defaults).join(\",\") || \"none\"})`);\n\n const denied = await clickFirstMatching(page, REJECT_SELECTORS, 2000);\n this.logAct(actionTimeline, actionSequence, denied ? \"click:reject\" : \"click:accept-or-none\");\n if (!denied) await clickFirstMatching(page, ACCEPT_SELECTORS, 1500);\n phase = \"post-accept\";\n await page.waitForTimeout(1200);\n const after = await readConsent();\n this.logAct(actionTimeline, actionSequence, `consent:after(${Object.keys(after).join(\",\") || \"none\"})`);\n await this.snap(page, \"consent-mode-v2\", \"01-after-choice\", screenshots, actionTimeline, actionSequence);\n\n const storageAfter = await this.snapshotStorage(page);\n const hasConsentMode = Object.keys(defaults).length > 0 || Object.keys(after).length > 0;\n const gaCookies = storageAfter.cookies.filter((c) => /^_ga|_gid|_gat|_gcl/i.test(c));\n const analyticsState = after.analytics_storage ?? defaults.analytics_storage ?? \"unset\";\n const adState = after.ad_storage ?? defaults.ad_storage ?? \"unset\";\n const mismatch =\n (analyticsState === \"denied\" && gaCookies.length > 0) ||\n (adState === \"denied\" && googleRequests.some((u) => /doubleclick|googleadservices/i.test(u)));\n\n const noteParts = [\n `consent-mode states: analytics_storage=${analyticsState}, ad_storage=${adState}, ad_user_data=${\n after.ad_user_data ?? defaults.ad_user_data ?? \"unset\"\n }, ad_personalization=${after.ad_personalization ?? defaults.ad_personalization ?? \"unset\"}`,\n `google requests: ${googleRequests.length}`,\n `ga cookies: ${gaCookies.length || \"none\"}`,\n hasConsentMode\n ? mismatch\n ? \"Zustand und Verhalten widersprechen sich.\"\n : \"Zustand und Verhalten stimmen überein.\"\n : \"Kein Consent Mode (dataLayer) gefunden — nicht prüfbar.\",\n ];\n\n evidence.push({\n scenario: \"consent-mode-v2\",\n status: !hasConsentMode ? \"not-checkable\" : mismatch ? \"suspicious\" : \"passed\",\n note: noteParts.join(\" · \"),\n actionSequence,\n actionTimeline,\n requestTimeline: timeline,\n storageBefore,\n storageAfter,\n screenshots,\n screenshotPath: screenshots[0]?.path,\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n\n if (!hasConsentMode) {\n failedScenarios.push(\"consent-mode-v2\");\n } else if (mismatch) {\n violations.push({\n id: `consent-mode-v2-${Date.now()}`,\n ruleId: \"consent-mode-mismatch\",\n scenario: \"consent-mode-v2\",\n trackerName: \"Google Consent Mode\",\n trackerCategory: \"analytics\",\n requestUrl: googleRequests[0] || config.targetUrl,\n method: \"GET\",\n timestamp: new Date().toISOString(),\n description: \"Consent-Mode-Zustand und tatsächliche Google-Requests/Cookies widersprechen sich.\",\n });\n failedScenarios.push(\"consent-mode-v2\");\n } else {\n passedScenarios.push(\"consent-mode-v2\");\n }\n } catch (err) {\n evidence.push({\n scenario: \"consent-mode-v2\" as never,\n status: \"not-checkable\",\n note: `Szenario mit Fehler abgebrochen: ${String(err).slice(0, 120)}`,\n actionSequence: [],\n requestTimeline: [],\n storageBefore: { cookies: [], localStorageKeys: [], sessionStorageKeys: [] },\n storageAfter: { cookies: [], localStorageKeys: [], sessionStorageKeys: [] },\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n failedScenarios.push(\"consent-mode-v2\");\n } finally {\n await context.close().catch(() => {});\n }\n }\n\n private async runEmbedScenario(\n browser: Browser,\n config: GateConfig,\n targetOrigin: string,\n violations: TrackerViolation[],\n passedScenarios: ChaosScenario[],\n failedScenarios: ChaosScenario[],\n evidence: EvidenceRecord[]\n ): Promise<void> {\n const context = await browser.newContext();\n const page = await context.newPage();\n const timeline: RequestEvent[] = [];\n const actionSequence: string[] = [];\n const actionTimeline: { at: string; action: string }[] = [];\n const screenshots: { label: string; path: string; at: string }[] = [];\n\n page.on(\"request\", (req) => {\n const hit = identifyTracker(req.url());\n // Embeds sind oft cross-origin — absichtlich NICHT auf targetOrigin filtern\n timeline.push({\n at: new Date().toISOString(),\n url: req.url(),\n trackerName: hit?.name,\n phase: \"pre-consent\",\n });\n if (hit && /youtube|maps|facebook|twitter|embed|chat|widget/i.test(hit.name)) {\n violations.push({\n id: `embed-leaks-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,\n ruleId: \"pre-consent-embed\",\n scenario: \"embed-leaks\",\n trackerName: hit.name,\n trackerCategory: hit.category,\n requestUrl: req.url(),\n method: req.method(),\n timestamp: new Date().toISOString(),\n description: `${hit.name} (Embed) kontaktiert Dritte vor Consent-Freigabe.`,\n });\n }\n });\n\n try {\n await page.goto(config.targetUrl, { waitUntil: \"domcontentloaded\", timeout: config.timeoutMs });\n this.logAct(actionTimeline, actionSequence, \"goto\");\n const storageBefore = await this.snapshotStorage(page);\n\n const EMBED_SCOPE = \"iframe, [data-src*='youtube'], [data-src*='maps'], .fb-video, .twitter-tweet\";\n const embedsEval = await page\n .evaluate(() => {\n const nodes = Array.from(\n document.querySelectorAll(\"iframe, [data-src*='youtube'], [data-src*='maps'], .fb-video, .twitter-tweet\")\n );\n return nodes.map((n) => {\n const el = n as HTMLElement;\n return {\n tag: el.tagName.toLowerCase(),\n src: el.getAttribute(\"src\") || el.getAttribute(\"data-src\") || \"\",\n visible: !!(el.offsetParent || el.getClientRects().length),\n };\n });\n })\n .catch(() => null as { tag: string; src: string; visible: boolean }[] | null);\n const embeds = embedsEval ?? [];\n const embedsEvalOk = embedsEval !== null;\n\n this.logAct(actionTimeline, actionSequence, `embeds:found(${embeds.length})`);\n await page.waitForTimeout(1500);\n // Lazy-Embeds aktivieren: scrollen\n await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight / 2)).catch(() => {});\n this.logAct(actionTimeline, actionSequence, \"scroll:half\");\n await page.waitForTimeout(1500);\n await this.snap(page, \"embed-leaks\", \"01-embeds\", screenshots, actionTimeline, actionSequence);\n\n const storageAfter = await this.snapshotStorage(page);\n const embedLeaks = timeline.filter((e) => e.trackerName && /youtube|maps|facebook|twitter/i.test(e.trackerName));\n\n if (embeds.length === 0 && embedLeaks.length === 0) {\n // Nicht anwendbar (keine Embeds vorhanden) ≠ nicht prüfbar (Erkennung scheiterte)\n const status: EvidenceRecord[\"status\"] = embedsEvalOk ? \"not-applicable\" : \"not-checkable\";\n evidence.push({\n scenario: \"embed-leaks\",\n status,\n note: embedsEvalOk\n ? `Nicht anwendbar: keine eingebetteten Inhalte im Suchumfang vorhanden (${EMBED_SCOPE}).`\n : `DOM-Auswertung der Embeds fehlgeschlagen — Erkennung nicht prüfbar (Suchumfang: ${EMBED_SCOPE}).`,\n actionSequence,\n actionTimeline,\n requestTimeline: timeline,\n storageBefore,\n storageAfter,\n screenshots,\n screenshotPath: screenshots[0]?.path,\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n if (!embedsEvalOk) failedScenarios.push(\"embed-leaks\");\n return;\n }\n\n const status: EvidenceRecord[\"status\"] = embedLeaks.length > 0 ? \"suspicious\" : \"passed\";\n evidence.push({\n scenario: \"embed-leaks\",\n status,\n note:\n status === \"passed\"\n ? `${embeds.length} Embed(s) gefunden, keine Drittanbieter-Requests vor Freigabe.`\n : `${embedLeaks.length} Embed-/Widget-Request(s) vor Consent-Freigabe.`,\n actionSequence,\n actionTimeline,\n requestTimeline: timeline,\n storageBefore,\n storageAfter,\n screenshots,\n screenshotPath: screenshots[0]?.path,\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n\n if (status === \"passed\") passedScenarios.push(\"embed-leaks\");\n else failedScenarios.push(\"embed-leaks\");\n } catch (err) {\n evidence.push({\n scenario: \"embed-leaks\" as never,\n status: \"not-checkable\",\n note: `Szenario mit Fehler abgebrochen: ${String(err).slice(0, 120)}`,\n actionSequence: [],\n requestTimeline: [],\n storageBefore: { cookies: [], localStorageKeys: [], sessionStorageKeys: [] },\n storageAfter: { cookies: [], localStorageKeys: [], sessionStorageKeys: [] },\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n failedScenarios.push(\"embed-leaks\");\n } finally {\n await context.close().catch(() => {});\n }\n }\n\n private async runCmpFailureScenario(\n browser: Browser,\n config: GateConfig,\n targetOrigin: string,\n violations: TrackerViolation[],\n passedScenarios: ChaosScenario[],\n failedScenarios: ChaosScenario[],\n evidence: EvidenceRecord[]\n ): Promise<void> {\n const context = await browser.newContext();\n const page = await context.newPage();\n const timeline: RequestEvent[] = [];\n const actionSequence: string[] = [];\n const actionTimeline: { at: string; action: string }[] = [];\n const screenshots: { label: string; path: string; at: string }[] = [];\n\n page.on(\"request\", (req) => {\n const frameUrl = req.frame()?.url() || page.url();\n if (!isOnTargetOrigin(frameUrl, targetOrigin)) return;\n const hit = identifyTracker(req.url());\n timeline.push({ at: new Date().toISOString(), url: req.url(), trackerName: hit?.name, phase: \"pre-consent\" });\n if (hit) {\n violations.push({\n id: `cmp-failure-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,\n ruleId: \"pre-consent-tracking\",\n scenario: \"cmp-failure\",\n trackerName: hit.name,\n trackerCategory: hit.category,\n requestUrl: req.url(),\n method: req.method(),\n timestamp: new Date().toISOString(),\n description: `${hit.name} startet, obwohl das CMP nicht verfügbar/verzögert ist.`,\n });\n }\n });\n\n try {\n // CMP stark verzögern (2.5s) statt hart blockieren — realistischer Timeout-Fall\n await page.route(\n (url) => {\n const href = url.href;\n if (href.startsWith(targetOrigin)) return false;\n return /cookiebot|onetrust|cookielaw|usercentrics|iubenda|didomi|axept|tealium|consentmanager|borlabs|klaro|etracker/i.test(\n href\n );\n },\n async (route) => {\n await new Promise((r) => setTimeout(r, 2500));\n await route.continue().catch(() => route.abort().catch(() => {}));\n }\n );\n this.logAct(actionTimeline, actionSequence, \"route:cmp-delay-2500ms\");\n\n await page.goto(config.targetUrl, { waitUntil: \"domcontentloaded\", timeout: config.timeoutMs });\n this.logAct(actionTimeline, actionSequence, \"goto\");\n const storageBefore = await this.snapshotStorage(page);\n await page.waitForTimeout(2000);\n this.logAct(actionTimeline, actionSequence, \"wait:window-2000ms\");\n await this.snap(page, \"cmp-failure\", \"01-delay-window\", screenshots, actionTimeline, actionSequence);\n\n // Zweite Phase: CMP hart abbrechen\n await page.unrouteAll().catch(() => {});\n await page.route(\n (url) => {\n const href = url.href;\n if (href.startsWith(targetOrigin)) return false;\n return /cookiebot|onetrust|cookielaw|usercentrics|iubenda|didomi|axept|tealium|consentmanager|borlabs|klaro|etracker/i.test(\n href\n );\n },\n (route) => route.abort()\n );\n this.logAct(actionTimeline, actionSequence, \"route:cmp-abort\");\n await page.reload({ waitUntil: \"domcontentloaded\", timeout: config.timeoutMs }).catch(() => {});\n await page.waitForTimeout(1800);\n this.logAct(actionTimeline, actionSequence, \"reload:without-cmp\");\n await this.snap(page, \"cmp-failure\", \"02-cmp-abort\", screenshots, actionTimeline, actionSequence);\n\n const storageAfter = await this.snapshotStorage(page);\n const leaks = timeline.filter((e) => e.trackerName);\n const status: EvidenceRecord[\"status\"] = leaks.length > 0 ? \"suspicious\" : \"passed\";\n\n evidence.push({\n scenario: \"cmp-failure\",\n status,\n note:\n status === \"passed\"\n ? \"Kein Tracking im Zeitfenster bei verzögertem oder ausgefallenem CMP.\"\n : `${leaks.length} Tracker im Zeitfenster bei verzögertem/defektem CMP.`,\n actionSequence,\n actionTimeline,\n requestTimeline: timeline,\n storageBefore,\n storageAfter,\n screenshots,\n screenshotPath: screenshots[0]?.path,\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n\n if (status === \"passed\") passedScenarios.push(\"cmp-failure\");\n else failedScenarios.push(\"cmp-failure\");\n } catch (err) {\n evidence.push({\n scenario: \"cmp-failure\" as never,\n status: \"not-checkable\",\n note: `Szenario mit Fehler abgebrochen: ${String(err).slice(0, 120)}`,\n actionSequence: [],\n requestTimeline: [],\n storageBefore: { cookies: [], localStorageKeys: [], sessionStorageKeys: [] },\n storageAfter: { cookies: [], localStorageKeys: [], sessionStorageKeys: [] },\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n failedScenarios.push(\"cmp-failure\");\n } finally {\n await context.close().catch(() => {});\n }\n }\n\n private async runSubpageSpaScenario(\n browser: Browser,\n config: GateConfig,\n targetOrigin: string,\n violations: TrackerViolation[],\n passedScenarios: ChaosScenario[],\n failedScenarios: ChaosScenario[],\n evidence: EvidenceRecord[]\n ): Promise<void> {\n const context = await browser.newContext();\n const page = await context.newPage();\n const timeline: RequestEvent[] = [];\n const actionSequence: string[] = [];\n const actionTimeline: { at: string; action: string }[] = [];\n const screenshots: { label: string; path: string; at: string }[] = [];\n const storageBefore = await this.snapshotStorage(page);\n\n const capture = (phase: RequestEvent[\"phase\"], req: import(\"playwright\").Request) => {\n const frameUrl = req.frame()?.url() || page.url();\n if (!isOnTargetOrigin(frameUrl, targetOrigin)) return;\n const hit = identifyTracker(req.url());\n timeline.push({ at: new Date().toISOString(), url: req.url(), trackerName: hit?.name, trackerCategory: hit?.category, phase });\n if (hit && phase === \"pre-consent\") {\n violations.push({\n id: `subpage-spa-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,\n ruleId: \"pre-consent-tracking\",\n scenario: \"subpage-spa\",\n trackerName: hit.name,\n trackerCategory: hit.category,\n requestUrl: req.url(),\n method: req.method(),\n timestamp: new Date().toISOString(),\n description: `${hit.name} feuert auf Unterseite/SPA-Navigation ohne Consent.`,\n });\n }\n };\n page.on(\"request\", (req) => capture(\"pre-consent\", req));\n\n try {\n // (a) Direkteinstieg Unterseite (typische Pfade)\n const subpaths = [\"/blog/\", \"/kontakt.html\", \"/shop/\", \"/impressum.html\"];\n for (const p of subpaths) {\n await page.goto(`${targetOrigin}${p}`, { waitUntil: \"domcontentloaded\", timeout: config.timeoutMs }).catch(() => {});\n this.logAct(actionTimeline, actionSequence, `goto:subpage${p}`);\n await page.waitForTimeout(600);\n }\n await this.snap(page, \"subpage-spa\", \"01-subpages\", screenshots, actionTimeline, actionSequence);\n\n // (b) SPA-Navigation ohne Reload: pushState + click auf interne Links\n await page.goto(config.targetUrl, { waitUntil: \"domcontentloaded\", timeout: config.timeoutMs });\n this.logAct(actionTimeline, actionSequence, \"goto:root\");\n await page.evaluate(() => {\n history.pushState({}, \"\", \"/spa-route-1\");\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n }).catch(() => {});\n this.logAct(actionTimeline, actionSequence, \"spa:pushState\");\n await page.waitForTimeout(800);\n\n // Interne Links klicken (same-origin), kein Reload\n const clicked = await page.evaluate(() => {\n const a = Array.from(document.querySelectorAll(\"a[href]\")).find((el) => {\n try {\n const u = new URL(el.getAttribute(\"href\") || \"\", location.href);\n return u.origin === location.origin && !u.hash;\n } catch {\n return false;\n }\n });\n if (a) {\n (a as HTMLElement).click();\n return true;\n }\n return false;\n }).catch(() => false);\n this.logAct(actionTimeline, actionSequence, clicked ? \"spa:click-internal\" : \"spa:no-internal-link\");\n await page.waitForTimeout(1000);\n await this.snap(page, \"subpage-spa\", \"02-after-spa\", screenshots, actionTimeline, actionSequence);\n\n const storageAfter = await this.snapshotStorage(page);\n const leaks = timeline.filter((e) => e.trackerName && e.phase === \"pre-consent\");\n const status: EvidenceRecord[\"status\"] = leaks.length > 0 ? \"suspicious\" : \"passed\";\n\n evidence.push({\n scenario: \"subpage-spa\",\n status,\n note:\n status === \"passed\"\n ? \"Kein unconsent-Tracking auf Unterseiten oder bei SPA-Navigation.\"\n : `${leaks.length} Tracker auf Unterseite/SPA ohne Consent.`,\n actionSequence,\n actionTimeline,\n requestTimeline: timeline,\n storageBefore,\n storageAfter,\n screenshots,\n screenshotPath: screenshots[0]?.path,\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n\n if (status === \"passed\") passedScenarios.push(\"subpage-spa\");\n else failedScenarios.push(\"subpage-spa\");\n } catch (err) {\n evidence.push({\n scenario: \"subpage-spa\" as never,\n status: \"not-checkable\",\n note: `Szenario mit Fehler abgebrochen: ${String(err).slice(0, 120)}`,\n actionSequence: [],\n requestTimeline: [],\n storageBefore: { cookies: [], localStorageKeys: [], sessionStorageKeys: [] },\n storageAfter: { cookies: [], localStorageKeys: [], sessionStorageKeys: [] },\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n failedScenarios.push(\"subpage-spa\");\n } finally {\n await context.close().catch(() => {});\n }\n }\n\n private async runBannerIgnoredScenario(\n browser: Browser,\n config: GateConfig,\n targetOrigin: string,\n violations: TrackerViolation[],\n passedScenarios: ChaosScenario[],\n failedScenarios: ChaosScenario[],\n evidence: EvidenceRecord[]\n ): Promise<void> {\n const context = await browser.newContext();\n const page = await context.newPage();\n const timeline: RequestEvent[] = [];\n const actionSequence: string[] = [];\n const actionTimeline: { at: string; action: string }[] = [];\n const screenshots: { label: string; path: string; at: string }[] = [];\n const phase: RequestEvent[\"phase\"] = \"pre-consent\";\n\n page.on(\"request\", (req) => {\n const frameUrl = req.frame()?.url() || page.url();\n if (!isOnTargetOrigin(frameUrl, targetOrigin)) return;\n const hit = identifyTracker(req.url());\n timeline.push({ at: new Date().toISOString(), url: req.url(), trackerName: hit?.name, trackerCategory: hit?.category, phase });\n if (hit) {\n violations.push({\n id: `banner-ignored-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,\n ruleId: \"pre-consent-tracking\",\n scenario: \"banner-ignored\",\n trackerName: hit.name,\n trackerCategory: hit.category,\n requestUrl: req.url(),\n method: req.method(),\n timestamp: new Date().toISOString(),\n description: `${hit.name} startet ohne Consent-Klick (Timer/Scroll/Interaktion).`,\n });\n }\n });\n\n try {\n await page.goto(config.targetUrl, { waitUntil: \"domcontentloaded\", timeout: config.timeoutMs });\n this.logAct(actionTimeline, actionSequence, \"goto\");\n const storageBefore = await this.snapshotStorage(page);\n await this.snap(page, \"banner-ignored\", \"01-loaded\", screenshots, actionTimeline, actionSequence);\n\n // (a) warten ohne Klick\n await page.waitForTimeout(2500);\n this.logAct(actionTimeline, actionSequence, \"wait:2500ms\");\n\n // (b) scrollen\n await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)).catch(() => {});\n this.logAct(actionTimeline, actionSequence, \"scroll:bottom\");\n await page.waitForTimeout(1200);\n\n // (c) Mouse/Input ohne Banner-Button\n await page.mouse.move(120, 200).catch(() => {});\n await page.mouse.click(120, 200).catch(() => {});\n this.logAct(actionTimeline, actionSequence, \"click:page-body\");\n await page.waitForTimeout(1500);\n\n // (d) Tastatureingabe (z. B. Suche) — kein Consent\n await page.keyboard.type(\"test\").catch(() => {});\n this.logAct(actionTimeline, actionSequence, \"type:test\");\n await page.waitForTimeout(800);\n\n await this.snap(page, \"banner-ignored\", \"02-after-interact\", screenshots, actionTimeline, actionSequence);\n const storageAfter = await this.snapshotStorage(page);\n const leaks = timeline.filter((e) => e.trackerName);\n const status: EvidenceRecord[\"status\"] = leaks.length > 0 ? \"suspicious\" : \"passed\";\n\n evidence.push({\n scenario: \"banner-ignored\",\n status,\n note:\n status === \"passed\"\n ? \"Kein Tracking allein durch Warten, Scrollen, Klick auf die Seite oder Tippen.\"\n : `${leaks.length} Tracker ohne Consent-Klick aktiv (Timer/Scroll/Interaktion).`,\n actionSequence,\n actionTimeline,\n requestTimeline: timeline,\n storageBefore,\n storageAfter,\n screenshots,\n screenshotPath: screenshots[0]?.path,\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n\n if (status === \"passed\") passedScenarios.push(\"banner-ignored\");\n else failedScenarios.push(\"banner-ignored\");\n } catch (err) {\n evidence.push({\n scenario: \"banner-ignored\" as never,\n status: \"not-checkable\",\n note: `Szenario mit Fehler abgebrochen: ${String(err).slice(0, 120)}`,\n actionSequence: [],\n requestTimeline: [],\n storageBefore: { cookies: [], localStorageKeys: [], sessionStorageKeys: [] },\n storageAfter: { cookies: [], localStorageKeys: [], sessionStorageKeys: [] },\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n failedScenarios.push(\"banner-ignored\");\n } finally {\n await context.close().catch(() => {});\n }\n }\n\n private async runRevocationScenario(\n browser: Browser,\n config: GateConfig,\n targetOrigin: string,\n violations: TrackerViolation[],\n passedScenarios: ChaosScenario[],\n failedScenarios: ChaosScenario[],\n evidence: EvidenceRecord[]\n ): Promise<void> {\n const context = await browser.newContext();\n const page = await context.newPage();\n const timeline: RequestEvent[] = [];\n const actionSequence: string[] = [];\n const actionTimeline: { at: string; action: string }[] = [];\n const screenshots: { label: string; path: string; at: string }[] = [];\n let phase: RequestEvent[\"phase\"] = \"pre-consent\";\n\n const identify = (url: string) => identifyTracker(url);\n page.on(\"request\", (req) => {\n const frameUrl = req.frame()?.url() || page.url();\n if (!isOnTargetOrigin(frameUrl, targetOrigin)) return;\n const hit = identify(req.url());\n timeline.push({\n at: new Date().toISOString(),\n url: req.url(),\n trackerName: hit?.name,\n phase,\n });\n if (hit) {\n const violation: TrackerViolation = {\n id: `consent-revoked-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,\n ruleId: phase === \"post-revoke\" ? \"tracking-after-revoke\" : \"pre-consent-tracking\",\n\n scenario: \"consent-revoked\",\n trackerName: hit.name,\n trackerCategory: hit.category,\n requestUrl: req.url(),\n method: req.method(),\n timestamp: new Date().toISOString(),\n description:\n phase === \"post-revoke\"\n ? `${hit.name} feuert nach Widerruf der Einwilligung.`\n : `Unauthorized ${hit.name} during consent-revoked scenario (${phase}).`,\n };\n if (phase === \"post-revoke\") {\n violations.push(violation);\n }\n }\n });\n\n try {\n await page.goto(config.targetUrl, { waitUntil: \"domcontentloaded\", timeout: config.timeoutMs });\n this.logAct(actionTimeline, actionSequence, \"goto\");\n const storageBefore = await this.snapshotStorage(page);\n await this.snap(page, \"consent-revoked\", \"01-banner\", screenshots, actionTimeline, actionSequence);\n\n const accepted = await clickFirstMatching(page, ACCEPT_SELECTORS, 2500);\n this.logAct(actionTimeline, actionSequence, accepted ? \"click:accept\" : \"click:accept-missing\");\n // Phase SOFORT am Klick — Re-Activation nach Accept ist legal\n phase = \"post-accept\";\n await page.waitForTimeout(800);\n await page.waitForTimeout(400);\n // Peak: Storage nach Accept — Referenz für den Widerruf-Diff\n const storageAfterAccept = await this.snapshotStorage(page);\n this.logAct(actionTimeline, actionSequence, \"snapshot:after-accept\");\n await this.snap(page, \"consent-revoked\", \"02-after-accept\", screenshots, actionTimeline, actionSequence);\n\n // Widerruf: Reject-Button, «Einstellungen» — Widerruf, oder Consent-Storage löschen\n // Phase VOR dem Klick setzen: Requests im Klick-Handler (Re-Arm) sind post-revoke.\n let revokeTargetVisible = false;\n for (const sel of REJECT_SELECTORS) {\n const vis = await page\n .locator(sel)\n .first()\n .isVisible({ timeout: 300 })\n .catch(() => false);\n if (vis) {\n revokeTargetVisible = true;\n break;\n }\n }\n if (revokeTargetVisible) {\n phase = \"post-revoke\";\n this.logAct(actionTimeline, actionSequence, \"phase:post-revoke\");\n }\n const revoked = await clickFirstMatching(page, REJECT_SELECTORS, 2500);\n this.logAct(actionTimeline, actionSequence, revoked ? \"click:revoke\" : \"click:revoke-missing\");\n\n if (!revoked && !accepted) {\n const storageAfter = await this.snapshotStorage(page);\n evidence.push({\n scenario: \"consent-revoked\",\n status: \"not-checkable\",\n note: \"Weder Accept- noch Revoke-Button auffindbar — Widerruf nicht prüfbar (kein grünes Häkchen).\",\n actionSequence,\n actionTimeline,\n requestTimeline: timeline,\n storageBefore,\n storageAfter,\n screenshots,\n screenshotPath: screenshots[0]?.path,\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n failedScenarios.push(\"consent-revoked\");\n return;\n }\n\n if (!revoked) {\n // Storage-Wipe ist kein Widerruf-Click — nicht prüfbar (nie grün).\n actionSequence.push(\"fallback:storage-wipe-skipped\");\n const storageAfter = await this.snapshotStorage(page);\n evidence.push({\n scenario: \"consent-revoked\",\n status: \"not-checkable\",\n note: \"Kein Widerruf-Button — Persistenz/Widerruf nicht prüfbar.\",\n actionSequence,\n actionTimeline,\n requestTimeline: timeline,\n storageBefore,\n storageAfter,\n screenshots,\n screenshotPath: screenshots[0]?.path,\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n failedScenarios.push(\"consent-revoked\");\n return;\n }\n\n if (!accepted) {\n // Kein Accept-Click = nichts zu widerrufen. Nie \"bestanden\" ohne erteilte Einwilligung.\n const storageAfter = await this.snapshotStorage(page);\n evidence.push({\n scenario: \"consent-revoked\",\n status: \"not-checkable\",\n note: \"Widerruf nicht prüfbar — keine vorherige Einwilligung erteilt (Accept-Button fehlte).\",\n actionSequence,\n actionTimeline,\n requestTimeline: timeline,\n storageBefore,\n storageAfter,\n storageAfterAccept,\n screenshots,\n screenshotPath: screenshots[0]?.path,\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n failedScenarios.push(\"consent-revoked\");\n return;\n }\n\n await page.waitForTimeout(300);\n // Gezielte Aktivität nach Widerruf: Seitenwechsel + Events, dann beobachten\n const observationMs = 2000;\n await page\n .goto(`${targetOrigin}/after-revoke`, { waitUntil: \"domcontentloaded\", timeout: config.timeoutMs })\n .catch(() => {});\n this.logAct(actionTimeline, actionSequence, \"post-revoke:goto\");\n await page.evaluate(() => {\n window.dispatchEvent(new Event(\"scroll\"));\n window.dispatchEvent(new Event(\"click\"));\n document.body?.dispatchEvent(new MouseEvent(\"click\", { bubbles: true }));\n }).catch(() => {});\n this.logAct(actionTimeline, actionSequence, `post-revoke:events observe=${observationMs}ms`);\n await page.waitForTimeout(observationMs);\n\n const storageAfter = await this.snapshotStorage(page);\n await this.snap(page, \"consent-revoked\", \"03-after-revoke\", screenshots, actionTimeline, actionSequence);\n // Anchored vendor patterns: Substring-Treffer wie \"megaMenu\" sind keine Tracker-IDs.\n const RESIDUAL_COOKIE =\n /^(_ga|_gid|_gat|_gcl|_fbp|_fbc|_tt|_ttp|_uetsid|_uetsid|li_s|li_at|hjSessionUser_|hjSession_|mkto_trk|hubspotutk|__hssc|__hstc|_opt_out)/i;\n const RESIDUAL_LS =\n /^(_ga|_gid|_gat|_gcl|_fbp|_fbc|_tt|_ttp|_hs|_hs_|mkto_|hubspot|munchkin|_gcl_)[A-Z0-9_.-]*$/i;\n const residual = [\n ...storageAfter.cookies.filter((c) => RESIDUAL_COOKIE.test(c.split(\"@\")[0])),\n ...storageAfter.localStorageKeys.filter((k) => RESIDUAL_LS.test(k)),\n ];\n\n const postRevokeTrackers = timeline.filter((e) => e.phase === \"post-revoke\" && e.trackerName);\n const status: EvidenceRecord[\"status\"] =\n postRevokeTrackers.length > 0 || residual.length > 0 ? \"suspicious\" : \"passed\";\n\n // Tatsächlicher Widerruf-Diff: Peak (nach Accept) vs. Endzustand\n const removedIds = [\n ...storageAfterAccept.cookies.filter((c) => !storageAfter.cookies.includes(c)),\n ...storageAfterAccept.localStorageKeys.filter((k) => !storageAfter.localStorageKeys.includes(k)),\n ];\n const keptIds = [\n ...storageAfter.cookies.filter((c) => storageAfterAccept.cookies.includes(c)),\n ...storageAfter.localStorageKeys.filter((k) => storageAfterAccept.localStorageKeys.includes(k)),\n ];\n\n evidence.push({\n scenario: \"consent-revoked\",\n status,\n note:\n (status === \"passed\"\n ? `Keine Tracker-Requests nach Widerruf (Beobachtungsfenster ${observationMs} ms mit Seitenwechsel und Events); keine auffälligen Tracking-IDs zurückgeblieben.`\n : `Nach Widerruf (Beobachtungsfenster ${observationMs} ms, Seitenwechsel + Events): ${postRevokeTrackers.length} Tracker-Request(s), ${residual.length} Rest-ID(s).`) +\n ` Widerruf-Diff: ${removedIds.length} Storage-Eintrag(e) entfernt, ${keptIds.length} verblieben (Peak nach Accept → Endzustand).`,\n actionSequence,\n actionTimeline,\n requestTimeline: timeline,\n storageBefore,\n storageAfter,\n storageAfterAccept,\n residualAfterRevoke: residual,\n screenshots,\n screenshotPath: screenshots[0]?.path,\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n\n if (status === \"passed\") {\n passedScenarios.push(\"consent-revoked\");\n } else {\n failedScenarios.push(\"consent-revoked\");\n }\n } catch (err) {\n evidence.push({\n scenario: \"consent-revoked\" as never,\n status: \"not-checkable\",\n note: `Szenario mit Fehler abgebrochen: ${String(err).slice(0, 120)}`,\n actionSequence: [],\n requestTimeline: [],\n storageBefore: { cookies: [], localStorageKeys: [], sessionStorageKeys: [] },\n storageAfter: { cookies: [], localStorageKeys: [], sessionStorageKeys: [] },\n targetUrl: config.targetUrl,\n checkedAt: new Date().toISOString(),\n });\n failedScenarios.push(\"consent-revoked\");\n } finally {\n await context.close().catch(() => {});\n }\n }\n\n}\n","import { TrackerCategory } from \"../../types/index.js\";\n\nexport interface TrackerSignature {\n name: string;\n category: TrackerCategory;\n patterns: RegExp[];\n}\n\nexport const KNOWN_TRACKERS: TrackerSignature[] = [\n {\n name: \"Google Analytics 4\",\n category: \"analytics\",\n patterns: [\n /google-analytics\\.com\\/g\\/collect/i,\n /analytics\\.google\\.com\\/g\\/collect/i,\n /google-analytics\\.com\\/j\\/collect/i,\n /google-analytics\\.com\\/collect/i,\n ],\n },\n {\n name: \"Google Tag Manager\",\n category: \"analytics\",\n patterns: [\n /googletagmanager\\.com\\/gtm\\.js/i,\n /googletagmanager\\.com\\/gtag\\/js/i,\n ],\n },\n {\n name: \"Meta (Facebook) Pixel\",\n category: \"marketing\",\n patterns: [\n /connect\\.facebook\\.net\\/.*\\/fbevents\\.js/i,\n /facebook\\.com\\/tr(\\/|\\?)/i,\n ],\n },\n {\n name: \"TikTok Pixel\",\n category: \"marketing\",\n patterns: [\n /analytics\\.tiktok\\.com\\/i18n\\/pixel/i,\n /analytics\\.tiktok\\.com\\/api\\/v2\\/pixel/i,\n ],\n },\n {\n name: \"Criteo OneTag\",\n category: \"marketing\",\n patterns: [\n /static\\.criteo\\.net\\/js\\/ld\\/ld\\.js/i,\n /gum\\.criteo\\.com\\/sync/i,\n ],\n },\n {\n name: \"Hotjar\",\n category: \"analytics\",\n patterns: [\n /static\\.hotjar\\.com\\/c\\/hotjar-/i,\n /script\\.hotjar\\.com\\/modules\\./i,\n ],\n },\n {\n name: \"LinkedIn Insight Tag\",\n category: \"marketing\",\n patterns: [\n /snap\\.licdn\\.com\\/li\\.lms-analytics\\/insight\\.min\\.js/i,\n /px\\.ads\\.linkedin\\.com\\/collect/i,\n ],\n },\n {\n name: \"Marketo Munchkin\",\n category: \"marketing\",\n patterns: [\n /munchkin\\.marketo\\.net\\/munchkin\\.js/i,\n /munchkin\\.marketo\\.net\\/munchkin/i,\n ],\n },\n {\n name: \"HubSpot\",\n category: \"marketing\",\n patterns: [\n /js\\.hs-scripts\\.com/i,\n /js\\.hs-analytics\\.net/i,\n /hubspot\\.com\\/_hcms\\//i,\n ],\n },\n {\n name: \"Matomo\",\n category: \"analytics\",\n patterns: [\n /matomo\\.php\\?/i,\n /matomo\\.js/i,\n /piwik\\.php\\?/i,\n ],\n },\n {\n name: \"YouTube Embed\",\n category: \"marketing\",\n patterns: [\n /youtube\\.com\\/embed\\//i,\n /youtube-nocookie\\.com\\/embed\\//i,\n /i\\.ytimg\\.com\\/vi\\//i,\n ],\n },\n {\n name: \"Google Maps Embed\",\n category: \"functional\",\n patterns: [\n /google\\.com\\/maps/i,\n /maps\\.googleapis\\.com\\//i,\n /maps\\.gstatic\\.com\\//i,\n ],\n },\n {\n name: \"Facebook Social Embed\",\n category: \"marketing\",\n patterns: [\n /facebook\\.com\\/plugins\\//i,\n /facebook\\.com\\/tr\\?/i,\n ],\n },\n {\n name: \"Twitter/X Embed\",\n category: \"marketing\",\n patterns: [\n /platform\\.twitter\\.com\\//i,\n /syndication\\.twitter\\.com\\//i,\n ],\n },\n];\n\nexport function identifyTracker(url: string): { name: string; category: TrackerCategory } | null {\n for (const tracker of KNOWN_TRACKERS) {\n for (const pattern of tracker.patterns) {\n if (pattern.test(url)) {\n return {\n name: tracker.name,\n category: tracker.category,\n };\n }\n }\n }\n return null;\n}\n","import { Page } from \"playwright\";\n\n/**\n * Vendor-specific first, then generic text/attribute fallbacks.\n * Ordered so real CMPs win over ambiguous `Accept` text matches.\n */\nexport const ACCEPT_SELECTORS = [\n // OneTrust\n \"#onetrust-accept-btn-handler\",\n \"#accept-recommended-btn-handler\",\n // Cookiebot\n \"#CybotCookiebotDialogBodyButtonAccept\",\n \"#CybotCookiebotDialogBodyLevelButtonLevelOptinAllowAll\",\n // Usercentrics (incl. shadow-host button via text)\n \"#usercentrics-root [data-testid='uc-accept-all-button']\",\n \"button[data-testid='uc-accept-all-button']\",\n // Consentmanager / Borlabs / Klaro\n \"#cmpbox-acceptall\",\n \".cmpboxbtn.cmpboxbtnyes\",\n \"#BorlabsCookieBox .btn-accept-all\",\n \"#klaro .klaro .confirm-button\",\n // Tealium (utag consent)\n \"#tealium-consent-banner .consent-accept\",\n \".tealium-consent-accept\",\n \"button[data-tealium-consent='accept']\",\n // iubenda\n \"#iubenda-cs-banner .iubenda-cs-accept-btn\",\n \".iubenda-cs-accept-btn\",\n \"#iubenda-cs-customize-btn + .iubenda-cs-accept-btn\",\n // etracker\n \"#ec-js-etracker-cmp .ec-cmp-accept\",\n \"#etrackerCookieConsent .accept\",\n \"button[data-et-consent='accept']\",\n // JustRelate\n \"#justrelate-consent .jr-accept\",\n \".justrelate-consent-accept\",\n \"button[data-jr-consent='accept']\",\n // Didomi / Axeptio\n \"#didomi-notice-agree-button\",\n \"#axeptio_btn_acceptAll\",\n // Generic\n \"#btn-accept\",\n \"#accept-all\",\n \"#cookie-accept\",\n \"button[data-action='accept']\",\n \"button:has-text('Alle akzeptieren')\",\n \"button:has-text('Akzeptieren')\",\n \"button:has-text('Accept all')\",\n \"button:has-text('Accept')\",\n \"button:has-text('Zustimmen')\",\n \".btn-accept\",\n];\n\nexport const REJECT_SELECTORS = [\n // OneTrust\n \"#onetrust-reject-all-handler\",\n // Cookiebot\n \"#CybotCookiebotDialogBodyButtonDecline\",\n \"#CybotCookiebotDialogBodyLevelButtonLevelOptinDeclineAll\",\n // Usercentrics\n \"#usercentrics-root [data-testid='uc-deny-all-button']\",\n \"button[data-testid='uc-deny-all-button']\",\n // Consentmanager / Borlabs / Klaro\n \"#cmpbox-createnecessary\",\n \".cmpboxbtn.cmpboxbtndeny\",\n \"#BorlabsCookieBox .btn-only-essential\",\n \"#klaro .klaro .decline-button\",\n // Tealium / iubenda / etracker / JustRelate\n \".tealium-consent-reject\",\n \"#tealium-consent-banner .consent-reject\",\n \".iubenda-cs-reject-btn\",\n \"#ec-js-etracker-cmp .ec-cmp-reject\",\n \"button[data-et-consent='reject']\",\n \".justrelate-consent-reject\",\n \"button[data-jr-consent='reject']\",\n // Didomi / Axeptio\n \"#didomi-notice-disagree-button\",\n \"#axeptio_btn_dismiss\",\n // Generic\n \"#btn-reject\",\n \"#btn-revoke\",\n // Sourcepoint\n \".sp_choice_type_12\",\n \".sp_choice_type_13\",\n \"button[title='Ablehnen']\",\n \"button[title='Einstellungen']\",\n \"#btn-revoke\",\n // Sourcepoint (Axel Springer, viele DACH-Publisher)\n \".sp_choice_type_11\",\n \"button[title='Alle akzeptieren']\",\n \"[aria-label='Alle akzeptieren']\",\n // Generic text fallbacks handled below\n \"#reject-all\",\n \"#cookie-reject\",\n \"button[data-action='reject']\",\n \"button:has-text('Ablehnen')\",\n \"button:has-text('Reject all')\",\n \"button:has-text('Reject')\",\n \"button:has-text('Nur notwendige')\",\n \"button:has-text('Essential only')\",\n \".btn-reject\",\n];\n\nexport type CmpName =\n | \"onetrust\"\n | \"cookiebot\"\n | \"usercentrics\"\n | \"consentmanager\"\n | \"borlabs\"\n | \"klaro\"\n | \"tealium\"\n | \"iubenda\"\n | \"etracker\"\n | \"justrelate\"\n | \"didomi\"\n | \"axeptio\"\n | \"generic\"\n | \"none\";\n\nconst CMP_MARKERS: { name: CmpName; test: (html: string) => boolean }[] = [\n { name: \"onetrust\", test: (h) => /onetrust|ot-sdk|optanon/i.test(h) },\n { name: \"cookiebot\", test: (h) => /cookiebot|CybotCookiebot|Cookiebot by Usercentrics/i.test(h) },\n { name: \"usercentrics\", test: (h) => /usercentrics|uc-sdk|data-testid=['\"]uc-/i.test(h) },\n { name: \"consentmanager\", test: (h) => /consentmanager\\.net|cmpbox/i.test(h) },\n { name: \"borlabs\", test: (h) => /BorlabsCookie/i.test(h) },\n { name: \"klaro\", test: (h) => /klaro/i.test(h) },\n { name: \"tealium\", test: (h) => /tealium|utag\\.gdpr|tealium-consent/i.test(h) },\n { name: \"iubenda\", test: (h) => /iubenda/i.test(h) },\n { name: \"etracker\", test: (h) => /etracker|ec-js-etracker/i.test(h) },\n { name: \"justrelate\", test: (h) => /justrelate|jr-consent/i.test(h) },\n { name: \"didomi\", test: (h) => /didomi/i.test(h) },\n { name: \"axeptio\", test: (h) => /axeptio|axept\\.io/i.test(h) },\n];\n\nexport function detectCmp(html: string): CmpName {\n for (const marker of CMP_MARKERS) {\n if (marker.test(html)) return marker.name;\n }\n if (/cookie|consent|banner/i.test(html)) return \"generic\";\n return \"none\";\n}\n\nexport async function clickFirstMatching(\n page: Page,\n selectors: string[],\n timeoutMs = 1500\n): Promise<boolean> {\n const perSelector = Math.max(250, timeoutMs / selectors.length);\n for (const selector of selectors) {\n try {\n const locator = page.locator(selector).first();\n const isVisible = await locator.isVisible({ timeout: perSelector }).catch(() => false);\n if (isVisible) {\n await locator.click({ timeout: 1000 }).catch(() => {});\n return true;\n }\n } catch {\n // Continue searching\n }\n }\n return false;\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport {\n FilePatch,\n FilePatchSchema,\n GateConfig,\n LeakReport,\n PullRequestResult,\n RemediationResult,\n ReviewVerdict,\n TrackerViolation,\n} from \"../../types/index.js\";\nimport { RemediationEngineInterface } from \"./types.js\";\nimport { CodeReviewer, CodeReviewerInterface } from \"./reviewer.js\";\nimport { PullRequestEngine, redactSecrets } from \"./pullRequest.js\";\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Injected when trackers are deferred. Activates `script[type=text/plain][data-src]`\n * and runs registered inits once consent is granted — including late accept clicks.\n */\nexport const CONSENT_ACTIVATION_RUNTIME = `<script data-cpcg=\"consent-activation\">\n(function () {\n if (window.__cpcgConsentRuntime) return;\n window.__cpcgConsentRuntime = true;\n window.__cpcgInits = window.__cpcgInits || [];\n\n function cpcgHasConsent() {\n try {\n var raw;\n // Explicit hook for custom CMPs\n if (window.__cpcgConsentGranted === true) return true;\n // Our own / simple stores\n raw = localStorage.getItem(\"cpcg_consent\");\n if (raw === \"accepted\") return true;\n raw = localStorage.getItem(\"consent\");\n if (raw === \"accepted\") return true;\n raw = localStorage.getItem(\"usercentrics-consent\");\n if (raw === \"accepted\") return true;\n // OneTrust: OptanonConsent is a URL-encoded query string (has consentId, groups=…)\n raw = localStorage.getItem(\"OptanonConsent\");\n if (raw) {\n if (raw === \"accepted\") return true;\n try {\n var q = new URLSearchParams(raw);\n if (q.get(\"status\") === \"accepted\" || q.get(\"groups\") && q.get(\"groups\").indexOf(\":1\") !== -1) return true;\n if (q.has(\"consentId\") && !/isIabGlobal=false;status=-1/.test(raw)) return true;\n } catch (e) {}\n }\n // Cookiebot: JSON with consented / stamp\n raw = localStorage.getItem(\"CookieConsent\");\n if (raw) {\n if (raw === \"accepted\" || raw === \"true\") return true;\n try {\n var cb = JSON.parse(raw);\n if (cb && (cb.consented === true || cb.necessary === true || cb.stamp)) return true;\n } catch (e) {}\n }\n // OneTrust OptanonConsent cookie fallback\n if (/(^|;\\s*)OptanonConsent=/.test(document.cookie)) return true;\n return false;\n } catch (_) {\n return false;\n }\n }\n\n function cpcgActivateDeferred() {\n if (!cpcgHasConsent()) return false;\n document.querySelectorAll('script[type=\"text/plain\"][data-src]').forEach(function (old) {\n if (old.getAttribute(\"data-cpcg-activated\") === \"1\") return;\n old.setAttribute(\"data-cpcg-activated\", \"1\");\n var s = document.createElement(\"script\");\n s.src = old.getAttribute(\"data-src\");\n s.async = old.async !== false;\n if (old.getAttribute(\"data-cookiecategory\")) {\n s.setAttribute(\"data-cookiecategory\", old.getAttribute(\"data-cookiecategory\"));\n }\n old.parentNode.insertBefore(s, old.nextSibling);\n });\n (window.__cpcgInits || []).forEach(function (fn) {\n try { fn(); } catch (e) { /* init failed */ }\n });\n window.__cpcgInits = [];\n return true;\n }\n\n window.cpcgActivateTrackers = cpcgActivateDeferred;\n window.cpcgGrantConsent = function () {\n window.__cpcgConsentGranted = true;\n return cpcgActivateDeferred();\n };\n\n [\"click\", \"storage\", \"consent\", \"usercentrics-consent\", \"OneTrustLoaded\"].forEach(function (evt) {\n window.addEventListener(evt, function () {\n setTimeout(cpcgActivateDeferred, 50);\n }, true);\n });\n document.addEventListener(\"click\", function () {\n setTimeout(cpcgActivateDeferred, 50);\n }, true);\n\n // Late accept: poll briefly while the page is open\n var tries = 0;\n var timer = setInterval(function () {\n tries += 1;\n if (cpcgActivateDeferred() || tries > 40) clearInterval(timer);\n }, 500);\n\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", cpcgActivateDeferred);\n } else {\n cpcgActivateDeferred();\n }\n})();\n</script>`;\n\nexport class RemediationEngine implements RemediationEngineInterface {\n private reviewer: CodeReviewerInterface;\n private prEngine: PullRequestEngine;\n\n constructor(\n reviewer?: CodeReviewerInterface,\n prEngine?: PullRequestEngine\n ) {\n this.reviewer = reviewer ?? new CodeReviewer();\n this.prEngine = prEngine ?? new PullRequestEngine();\n }\n\n async remediate(report: LeakReport, config: GateConfig): Promise<RemediationResult> {\n if (report.totalViolations === 0) {\n return {\n success: true,\n patches: [],\n commitMessage: \"No violations to remediate.\",\n };\n }\n\n try {\n // Step 1: Find candidate files in sourceDir\n const candidateFiles = await this.findCandidateSourceFiles(config.sourceDir);\n if (candidateFiles.length === 0) {\n return {\n success: false,\n patches: [],\n error: `No candidate source files found in source directory: ${config.sourceDir}`,\n };\n }\n\n // Step 2: Attempt LLM remediation if API key is configured, else fallback to deterministic rule engine\n let candidatePatches: FilePatch[] = [];\n if (config.apiKey) {\n candidatePatches = await this.remediateWithLlm(report, candidateFiles, config);\n }\n\n // If LLM returned no patches or no API key, use deterministic privacy rule engine\n if (candidatePatches.length === 0) {\n candidatePatches = await this.remediateWithRuleEngine(report, candidateFiles);\n }\n\n if (candidatePatches.length === 0) {\n return {\n success: false,\n patches: [],\n error: \"Could not identify and patch the leaking code in candidate source files.\",\n };\n }\n\n // Step 3: REVIEW AGENT QUALITY GATE (\"Keine Fehler im Code\")\n const reviewVerdict = await this.reviewer.review(candidatePatches, report, config);\n\n if (!reviewVerdict.passed) {\n return {\n success: false,\n patches: [],\n reviewVerdict,\n error: `Review Agent rejected candidate patches (Score: ${reviewVerdict.score}/100):\\n${reviewVerdict.comments.join(\"\\n\")}`,\n };\n }\n\n const approvedPatches = reviewVerdict.approvedPatches;\n\n // Step 4: Apply approved patches to filesystem (originals are kept for rollback)\n const originals = new Map<string, string>();\n for (const patch of approvedPatches) {\n originals.set(patch.filePath, patch.originalContent ?? (await fs.readFile(patch.filePath, \"utf-8\")));\n }\n const rollback = async (): Promise<void> => {\n for (const [file, content] of originals) {\n await fs.writeFile(file, content, \"utf-8\").catch(() => undefined);\n }\n };\n for (const patch of approvedPatches) {\n await fs.writeFile(patch.filePath, patch.patchedContent, \"utf-8\");\n }\n\n // Step 5: Pull Request Engine or Git commit (PR takes precedence over a plain commit)\n let commitHash: string | undefined;\n let pullRequest: PullRequestResult | undefined;\n const commitMessage = `fix(privacy): auto-remediate ${report.totalViolations} tracker leak(s) via CPCG`;\n\n try {\n if (config.createPr) {\n pullRequest = await this.prEngine.createPullRequest(\n approvedPatches,\n report,\n reviewVerdict,\n config\n );\n // The fix lives on the PR branch; restore the starting branch's working tree.\n await rollback();\n } else if (config.gitCommit) {\n const files = approvedPatches.map((p) => p.filePath);\n await execFileAsync(\"git\", [\"add\", \"--\", ...files]);\n const { stdout } = await execFileAsync(\"git\", [\"commit\", \"-m\", commitMessage, \"--\", ...files]);\n const hashMatch = stdout.match(/\\[.*?\\s+([a-f0-9]+)\\]/);\n commitHash = hashMatch ? hashMatch[1] : \"committed\";\n }\n } catch (gitErr) {\n await rollback();\n // Best effort: drop anything the failed step left staged (rollback only restores the working tree).\n await execFileAsync(\"git\", [\"reset\", \"-q\", \"--\", ...originals.keys()]).catch(() => undefined);\n return {\n success: false,\n patches: [],\n reviewVerdict,\n error: `Git/PR step failed; working-tree changes were rolled back and the index was reset: ${redactSecrets(\n gitErr instanceof Error ? gitErr.message : String(gitErr),\n config.githubToken\n )}`,\n };\n }\n\n return {\n success: true,\n patches: approvedPatches,\n reviewVerdict,\n commitHash,\n commitMessage,\n pullRequest,\n };\n } catch (err) {\n return {\n success: false,\n patches: [],\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n\n private async findCandidateSourceFiles(dir: string): Promise<string[]> {\n const candidates: string[] = [];\n const allowedExtensions = new Set([\".html\", \".htm\", \".jsx\", \".tsx\", \".js\", \".ts\", \".vue\", \".svelte\"]);\n\n async function walk(currentDir: string) {\n const entries = await fs.readdir(currentDir, { withFileTypes: true }).catch(() => []);\n for (const entry of entries) {\n const fullPath = path.join(currentDir, entry.name);\n if (entry.isDirectory()) {\n if (\n entry.name === \"node_modules\" ||\n entry.name === \".git\" ||\n entry.name === \"dist\" ||\n entry.name === \"reports\" ||\n entry.name === \"test-fixtures\" ||\n entry.name === \"tests\"\n ) {\n continue;\n }\n await walk(fullPath);\n } else if (entry.isFile() && allowedExtensions.has(path.extname(entry.name).toLowerCase())) {\n candidates.push(fullPath);\n }\n }\n }\n\n await walk(path.resolve(dir));\n return candidates;\n }\n\n /**\n * Deterministic Privacy Patcher: Analyzes violations and injects consent gates or CMP categorization attributes\n */\n private async remediateWithRuleEngine(\n report: LeakReport,\n candidateFiles: string[]\n ): Promise<FilePatch[]> {\n const patches: FilePatch[] = [];\n\n for (const filePath of candidateFiles) {\n const content = await fs.readFile(filePath, \"utf-8\");\n let updatedContent = content;\n let fileModified = false;\n\n for (const violation of report.violations) {\n // Fix Google Analytics / GTM leaks\n if (\n violation.trackerName.includes(\"Google\") &&\n (updatedContent.includes(\"googletagmanager.com\") ||\n updatedContent.includes(\"google-analytics.com\") ||\n updatedContent.includes(\"gtag(\"))\n ) {\n // Transform standard external script to type=\"text/plain\" data-cookiecategory=\"analytics\"\n const externalGtagRegex = /<script\\s+async\\s+src=\"https:\\/\\/www\\.googletagmanager\\.com\\/gtag\\/js\\?id=([^\"]+)\">\\s*<\\/script>/gi;\n if (externalGtagRegex.test(updatedContent)) {\n updatedContent = updatedContent.replace(\n externalGtagRegex,\n `<script type=\"text/plain\" data-cookiecategory=\"analytics\" data-src=\"https://www.googletagmanager.com/gtag/js?id=$1\"></script>`\n );\n fileModified = true;\n }\n\n // Wrap inline gtag & fetch tracking with consent validation + late re-activation\n const inlineGtagRegex =\n /<script>[\\s\\S]*?gtag\\(\\s*['\"]config['\"]\\s*,\\s*['\"]([^'\"]+)['\"][\\s\\S]*?<\\/script>/i;\n const inlineMatch = inlineGtagRegex.exec(updatedContent);\n if (inlineMatch && !updatedContent.includes('data-cpcg=\"deferred-init\"')) {\n const measurementId = inlineMatch[1]!;\n const inlineBeacon =\n /fetch\\(\"([^\"]*google-analytics\\.com\\/g\\/collect[^\"]*)\"/.exec(inlineMatch[0])?.[1];\n updatedContent = updatedContent.replace(\n inlineMatch[0],\n `<script data-cpcg=\"deferred-init\">\n // [CPCG Auto-Remediation]: run after explicit consent, including late accept\n window.__cpcgInits = window.__cpcgInits || [];\n window.__cpcgInits.push(function initAnalytics() {\n if (localStorage.getItem('cpcg_consent') !== 'accepted') return;\n window.dataLayer = window.dataLayer || [];\n function gtag(){dataLayer.push(arguments);}\n gtag('js', new Date());\n gtag('config', '${measurementId}');\n ${inlineBeacon ? `fetch(${JSON.stringify(inlineBeacon)}).catch(function () {});` : \"\"}\n });\n if (localStorage.getItem('cpcg_consent') === 'accepted' && window.cpcgActivateTrackers) {\n window.cpcgActivateTrackers();\n }\n </script>`\n );\n fileModified = true;\n }\n\n // Defer raw fetch/beacon leaks until consent (keep original tid/params)\n const beaconRe =\n /fetch\\(\"(https:\\/\\/www\\.google-analytics\\.com\\/g\\/collect[^\"]*)\"\\)\\.catch\\(\\s*(?:\\(\\)\\s*=>\\s*\\{\\}|function\\s*\\(\\)\\s*\\{\\s*\\})\\s*\\);?/g;\n let beaconFound = false;\n let capturedBeaconUrl = \"\";\n updatedContent = updatedContent.replace(beaconRe, (_m, url: string) => {\n beaconFound = true;\n if (!capturedBeaconUrl) capturedBeaconUrl = url;\n return `/* [CPCG Remediation]: beacon deferred to consent runtime */`;\n });\n if (beaconFound) {\n const beaconUrl =\n capturedBeaconUrl || \"https://www.google-analytics.com/g/collect?v=2&en=page_view\";\n updatedContent = updatedContent.replace(\n \"</body>\",\n ` <script data-cpcg=\"deferred-beacon\">\n window.__cpcgInits = window.__cpcgInits || [];\n window.__cpcgInits.push(function () {\n if (localStorage.getItem('cpcg_consent') !== 'accepted') return;\n fetch(${JSON.stringify(beaconUrl)}).catch(function () {});\n });\n </script>\n</body>`\n );\n fileModified = true;\n }\n }\n\n // Fix Meta Pixel leaks\n if (\n violation.trackerName.includes(\"Meta\") &&\n (updatedContent.includes(\"connect.facebook.net\") || updatedContent.includes(\"fbq(\"))\n ) {\n const metaRegex = /<script([^>]*)src=\"https:\\/\\/connect\\.facebook\\.net\\/([^\"]*)\"([^>]*)><\\/script>/gi;\n if (metaRegex.test(updatedContent)) {\n updatedContent = updatedContent.replace(\n metaRegex,\n (_m, pre, src, post) =>\n `<script${pre} type=\"text/plain\" data-cookiecategory=\"marketing\" data-src=\"https://connect.facebook.net/${src}\"${post}></script>`\n );\n fileModified = true;\n }\n // Inline fbq bootstrap: defer until consent\n if (updatedContent.includes(\"fbq(\") && !updatedContent.includes('data-cpcg=\"deferred-fbq\"')) {\n updatedContent = updatedContent.replace(\n /<script>\\s*(!function\\(f,b,e,v,n,t,s\\)[\\s\\S]*?fbq\\([\\s\\S]*?)<\\/script>/i,\n `<script data-cpcg=\"deferred-fbq\">\n window.__cpcgInits = window.__cpcgInits || [];\n window.__cpcgInits.push(function () {\n if (localStorage.getItem('cpcg_consent') !== 'accepted' && localStorage.getItem('OptanonConsent') !== 'accepted') return;\n $1\n });\n </script>`\n );\n if (updatedContent.includes('data-cpcg=\"deferred-fbq\"')) fileModified = true;\n }\n }\n\n // Fix Google Tag Manager container leaks (gtm.js bootstrap)\n if (\n violation.trackerName.includes(\"Google\") ||\n violation.trackerName.includes(\"Tag Manager\") ||\n updatedContent.includes(\"googletagmanager.com/gtm.js\")\n ) {\n const gtmScriptRegex = /<script\\s+async\\s+src=\"https:\\/\\/www\\.googletagmanager\\.com\\/gtm\\.js\\?id=([^\"]+)\">\\s*<\\/script>/gi;\n if (gtmScriptRegex.test(updatedContent)) {\n updatedContent = updatedContent.replace(\n gtmScriptRegex,\n `<script type=\"text/plain\" data-cookiecategory=\"analytics\" data-src=\"https://www.googletagmanager.com/gtm.js?id=$1\"></script>`\n );\n fileModified = true;\n }\n // GTM bootstrap IIFE: replace the whole script tag with Consent Mode + deferred load\n const gtmIifeScriptRegex =\n /<script>\\s*\\(function\\(w,d,s,l,i\\)\\{[\\s\\S]*?\\}\\)\\(window,document,'script','dataLayer','([^']+)'\\);?\\s*<\\/script>/i;\n if (gtmIifeScriptRegex.test(updatedContent) && !updatedContent.includes('data-cpcg=\"deferred-gtm\"')) {\n updatedContent = updatedContent.replace(\n gtmIifeScriptRegex,\n `<script data-cpcg=\"deferred-gtm\">\n // [CPCG]: Google Consent Mode v2 — default denied, granted after accept\n window.dataLayer = window.dataLayer || [];\n function gtag(){dataLayer.push(arguments);}\n gtag('consent', 'default', {\n ad_storage: 'denied',\n ad_user_data: 'denied',\n ad_personalization: 'denied',\n analytics_storage: 'denied',\n wait_for_update: 500\n });\n window.__cpcgInits = window.__cpcgInits || [];\n window.__cpcgInits.push(function () {\n if (localStorage.getItem('cpcg_consent') !== 'accepted') return;\n gtag('consent', 'update', {\n ad_storage: 'granted',\n ad_user_data: 'granted',\n ad_personalization: 'granted',\n analytics_storage: 'granted'\n });\n (function(w,d,s,l,i){var f=d.getElementsByTagName(s)[0],j=d.createElement(s);j.async=true;j.src='https://www.googletagmanager.com/gtm.js?id='+i;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer','$1');\n });\n </script>`\n );\n if (updatedContent.includes('data-cpcg=\"deferred-gtm\"')) fileModified = true;\n }\n }\n\n // Fix React/SPA tracker bootstraps (react-ga, ReactGA, gtag in effects)\n if (/\\.(jsx|tsx|js|ts|vue|svelte)$/i.test(filePath) || updatedContent.includes(\"ReactGA\") || updatedContent.includes(\"react-ga\")) {\n const reactGaInit =\n /ReactGA\\.initialize\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]\\s*\\)\\s*;?/g;\n if (reactGaInit.test(updatedContent) && !updatedContent.includes(\"deferred-reactga\")) {\n updatedContent = updatedContent.replace(\n reactGaInit,\n `/* data-cpcg=\"deferred-reactga\" */\n if (typeof window !== 'undefined' && localStorage.getItem('cpcg_consent') === 'accepted') {\n ReactGA.initialize('$1');\n } else {\n window.__cpcgInits = window.__cpcgInits || [];\n window.__cpcgInits.push(function(){ ReactGA.initialize('$1'); });\n }`\n );\n fileModified = true;\n }\n // gtag('config', ...) / gtag('js', ...) calls outside of already-wrapped inits\n if (\n /\\bgtag\\s*\\(\\s*['\"]config['\"]/.test(updatedContent) &&\n !updatedContent.includes(\"cpcgHasConsent\") &&\n !updatedContent.includes('data-cpcg=\"deferred-init\"')\n ) {\n updatedContent = updatedContent.replace(\n /(\\bgtag\\s*\\(\\s*['\"]config['\"]\\s*,\\s*['\"`][^'\"`]+['\"`]\\s*\\)\\s*;?)/g,\n `if (typeof window !== 'undefined' && localStorage.getItem('cpcg_consent') === 'accepted') { $1 }`\n );\n fileModified = true;\n }\n }\n }\n\n // Ensure activation runtime is present once anything is deferred (GTM, GA, Meta, …)\n if (\n updatedContent.includes('type=\"text/plain\"') &&\n !updatedContent.includes(\"cpcgConsentRuntime\")\n ) {\n updatedContent = updatedContent.replace(\n /(<\\/head>)/i,\n `${CONSENT_ACTIVATION_RUNTIME}\\n$1`\n );\n if (!updatedContent.includes(\"cpcgConsentRuntime\")) {\n updatedContent = CONSENT_ACTIVATION_RUNTIME + \"\\n\" + updatedContent;\n }\n fileModified = true;\n }\n\n if (fileModified && updatedContent !== content) {\n patches.push({\n filePath,\n originalContent: content,\n patchedContent: updatedContent,\n explanation: `Applied privacy remediation for: ${report.violations.map((v) => v.trackerName).join(\", \")}. Deferred tracker execution (incl. GTM/React) until explicit consent with post-accept re-activation.`,\n });\n }\n }\n\n return patches;\n }\n\n /**\n * LLM API Remediation: Queries OpenAI/Anthropic/Gemini to generate surgical code patches\n */\n private async remediateWithLlm(\n report: LeakReport,\n candidateFiles: string[],\n config: GateConfig\n ): Promise<FilePatch[]> {\n // Read the most relevant candidate file (max 1-2 files to preserve token economy)\n const filesData: { path: string; content: string }[] = [];\n for (const f of candidateFiles.slice(0, 3)) {\n const content = await fs.readFile(f, \"utf-8\");\n filesData.push({ path: f, content });\n }\n\n const systemPrompt = `You are the Cuonztech Privacy Auto-Remediation Agent.\nYour job is to fix privacy leaks detected by the Privacy Chaos Scanner.\nReturn ONLY valid JSON matching this structure:\n{\n \"patches\": [\n {\n \"filePath\": \"string\",\n \"patchedContent\": \"string\",\n \"explanation\": \"string\"\n }\n ]\n}\nMake minimal, surgical changes (e.g. wrap tracking code in consent checks, add data-cookiecategory attributes). Do NOT remove functional UI code.`;\n\n const userPrompt = `A privacy leak was detected:\nViolations: ${JSON.stringify(report.violations, null, 2)}\n\nSource Files:\n${filesData.map((f) => `--- File: ${f.path} ---\\n${f.content}\\n`).join(\"\\n\")}\n\nGenerate the patched content to eliminate all unconsented tracker executions.`;\n\n try {\n if (config.llmProvider && config.llmProvider !== \"openai\") {\n // Klarheit statt Stillstand: nur OpenAI ist implementiert.\n throw new Error(\n `LLM-Provider '${config.llmProvider}' ist noch nicht implementiert (nur openai). Deterministische Regel-Engine greift stattdessen.`\n );\n }\n if (config.llmProvider === \"openai\" || !config.llmProvider) {\n const response = await fetch(\"https://api.openai.com/v1/chat/completions\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${config.apiKey}`,\n },\n signal: AbortSignal.timeout(60000),\n body: JSON.stringify({\n model: config.llmModel || \"gpt-4o\",\n response_format: { type: \"json_object\" },\n messages: [\n { role: \"system\", content: systemPrompt },\n { role: \"user\", content: userPrompt },\n ],\n temperature: 0.1,\n }),\n });\n\n if (response.ok) {\n const json = await response.json() as { choices?: { message?: { content?: string } }[] };\n const reply = json.choices?.[0]?.message?.content;\n if (reply) {\n const parsed = JSON.parse(reply) as { patches?: unknown };\n if (Array.isArray(parsed.patches)) {\n return await this.sanitizeLlmPatches(parsed.patches, candidateFiles);\n }\n }\n }\n }\n } catch (llmErr) {\n console.warn(\"⚠ LLM request failed, falling back to rule engine: \" + String(llmErr));\n }\n\n return [];\n }\n\n /**\n * LLM output is untrusted: validate against the schema, restrict to known candidate files\n * (no path traversal / arbitrary writes) and fill originalContent from disk for the Review Agent.\n */\n private async sanitizeLlmPatches(raw: unknown[], candidateFiles: string[]): Promise<FilePatch[]> {\n const allowed = new Map(candidateFiles.map((f) => [path.resolve(f), f]));\n const result: FilePatch[] = [];\n for (const item of raw) {\n const parsed = FilePatchSchema.safeParse(item);\n if (!parsed.success) continue;\n const resolved = path.resolve(parsed.data.filePath);\n const known = allowed.get(resolved);\n if (!known) {\n console.warn(`⚠ Ignoring LLM patch for unknown/out-of-scope file: ${parsed.data.filePath}`);\n continue;\n }\n const originalContent = await fs.readFile(known, \"utf-8\");\n result.push({ ...parsed.data, filePath: known, originalContent });\n }\n return result;\n }\n}\n","import ts from \"typescript\";\nimport { FilePatch, GateConfig, LeakReport, ReviewVerdict } from \"../../types/index.js\";\nimport { LEGAL_DISCLAIMER } from \"../legal/disclaimer.js\";\n\nexport interface CodeReviewerInterface {\n review(\n patches: FilePatch[],\n report: LeakReport,\n config: GateConfig\n ): Promise<ReviewVerdict>;\n}\n\n/** Code-level consent guard (checked on comment-stripped code, so a `// consent` comment does not count). */\nconst CONSENT_GUARD =\n /(getItem\\(\\s*['\"`][^'\"`]*consent[^'\"`]*['\"`]\\s*\\)|\\bhasConsent\\b|\\bconsentGiven\\b|\\bisConsented\\b|\\bcookiecategory\\b|\\bgetConsent\\w*\\()/i;\n\ninterface TrackerMarker {\n match: (trackerName: string) => boolean;\n code: RegExp;\n}\n\nconst TRACKER_MARKERS: TrackerMarker[] = [\n {\n match: (n) => /google|gtm|analytics/i.test(n),\n // gtag('consent'|'set'...) is Consent Mode API, not a tracker fire; function gtag(){} is the helper\n code: /googletagmanager\\.com|google-analytics\\.com|\\bgtag\\s*\\(\\s*['\"](?!(?:consent|set)['\"])|\\bga\\s*\\(/i,\n },\n { match: (n) => /meta|facebook/i.test(n), code: /connect\\.facebook\\.net|facebook\\.com\\/tr|\\bfbq\\s*\\(/i },\n { match: (n) => /tiktok/i.test(n), code: /analytics\\.tiktok\\.com|\\bttq\\b/i },\n { match: (n) => /criteo/i.test(n), code: /criteo\\.(net|com)/i },\n { match: (n) => /hotjar/i.test(n), code: /hotjar\\.com|\\bhj\\s*\\(/i },\n { match: (n) => /linkedin/i.test(n), code: /licdn\\.com|ads\\.linkedin\\.com|_linkedin_partner_id/i },\n];\n\nconst JS_EXT = /\\.(js|mjs|cjs|jsx|ts|tsx)$/i;\nconst HTML_EXT = /\\.(html|htm)$/i;\n\nfunction stripComments(code: string): string {\n return code.replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\").replace(/(^|[^:\\\\'\"`])\\/\\/.*$/gm, \"$1\");\n}\n\nfunction syntaxErrors(code: string, fileName: string): string[] {\n const out = ts.transpileModule(code, {\n fileName,\n reportDiagnostics: true,\n compilerOptions: { jsx: ts.JsxEmit.Preserve, target: ts.ScriptTarget.ES2022 },\n });\n return (out.diagnostics ?? [])\n .filter((d) => d.category === ts.DiagnosticCategory.Error)\n .map((d) => {\n const msg = ts.flattenDiagnosticMessageText(d.messageText, \" \");\n const pos = d.file && d.start !== undefined ? d.file.getLineAndCharacterOfPosition(d.start) : undefined;\n return `[Syntax] ${fileName}${pos ? `:${pos.line + 1}:${pos.character + 1}` : \"\"} ${msg}`;\n });\n}\n\ninterface ScriptBlock {\n attrs: string;\n body: string;\n}\n\nfunction extractScripts(html: string): ScriptBlock[] {\n const blocks: ScriptBlock[] = [];\n const re = /<script\\b([^>]*)>([\\s\\S]*?)<\\/script\\s*>/gi;\n let m: RegExpExecArray | null;\n while ((m = re.exec(html)) !== null) {\n blocks.push({ attrs: m[1] ?? \"\", body: m[2] ?? \"\" });\n }\n return blocks;\n}\n\nfunction isExecutableJs(attrs: string): boolean {\n const type = /\\btype\\s*=\\s*[\"']?([^\"'\\s>]+)/i.exec(attrs)?.[1]?.toLowerCase();\n return !type || type === \"module\" || type.includes(\"javascript\");\n}\n\nfunction isBlockedByType(attrs: string): boolean {\n // Only type=\"text/plain\" makes a script inert; data-cookiecategory alone does not stop execution.\n return /\\btype\\s*=\\s*[\"']?text\\/plain/i.test(attrs);\n}\n\n/**\n * Returns the tracker usages in `code` (calls like gtag(...)/fbq(...)/ttq.x(...) and string literals that\n * contain tracker URLs) that are NOT protected by a consent guard. A usage is protected when it sits\n * - inside the `then` branch of an `if` whose condition references consent,\n * - on the right side of `consent && ...` / in a consent-conditional expression, or\n * - after an early-exit guard (`if (!consent) return;`) earlier in an enclosing block.\n */\nfunction findUnguardedTrackerUsages(code: string, fileName: string, marker: RegExp): number[] {\n const sf = ts.createSourceFile(fileName, code, ts.ScriptTarget.ES2022, true);\n const unguarded: number[] = [];\n\n const exitsEarly = (s: ts.Statement): boolean => {\n if (ts.isReturnStatement(s) || ts.isThrowStatement(s)) return true;\n if (ts.isBlock(s)) return s.statements.some(exitsEarly);\n return false;\n };\n\n const isGuarded = (node: ts.Node): boolean => {\n let child: ts.Node = node;\n for (let p: ts.Node | undefined = node.parent; p; child = p, p = p.parent) {\n if (ts.isIfStatement(p) && CONSENT_GUARD.test(p.expression.getText(sf)) && child === p.thenStatement) {\n return true;\n }\n if (\n ts.isBinaryExpression(p) &&\n p.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken &&\n child === p.right &&\n CONSENT_GUARD.test(p.left.getText(sf))\n ) {\n return true;\n }\n if (ts.isConditionalExpression(p) && child === p.whenTrue && CONSENT_GUARD.test(p.condition.getText(sf))) {\n return true;\n }\n if (ts.isBlock(p) || ts.isSourceFile(p)) {\n const stmts = (p as ts.Block | ts.SourceFile).statements;\n const idx = stmts.indexOf(child as ts.Statement);\n for (let i = 0; i < idx; i++) {\n const s = stmts[i];\n if (ts.isIfStatement(s) && CONSENT_GUARD.test(s.expression.getText(sf)) && exitsEarly(s.thenStatement)) {\n return true;\n }\n }\n }\n }\n return false;\n };\n\n const visit = (node: ts.Node): void => {\n let isUsage = false;\n if (ts.isCallExpression(node)) {\n // Match on callee + first string arg only — full getText() would pull in nested\n // function bodies and false-positive on `push(function(){ gtag(...) })`.\n const callee = node.expression.getText(sf);\n const firstStr = node.arguments.find(\n (a) => ts.isStringLiteral(a) || ts.isNoSubstitutionTemplateLiteral(a)\n );\n const head = firstStr ? `${callee}(${firstStr.getText(sf)}` : `${callee}(`;\n isUsage = marker.test(head);\n } else if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {\n isUsage = marker.test(node.text);\n }\n if (isUsage && !isGuarded(node)) {\n unguarded.push(sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1);\n }\n ts.forEachChild(node, visit);\n };\n visit(sf);\n return unguarded;\n}\n\nexport class CodeReviewer implements CodeReviewerInterface {\n async review(\n patches: FilePatch[],\n report: LeakReport,\n config: GateConfig\n ): Promise<ReviewVerdict> {\n const comments: string[] = [];\n const approvedPatches: FilePatch[] = [];\n const rejectedPatches: FilePatch[] = [];\n\n if (patches.length === 0) {\n return {\n passed: false,\n score: 0,\n comments: [\"No patches provided for review.\"],\n approvedPatches: [],\n rejectedPatches: [],\n };\n }\n\n for (const patch of patches) {\n const errors = this.reviewPatch(patch, report);\n if (errors.length === 0) {\n approvedPatches.push(patch);\n comments.push(`✔ [APPROVED] ${patch.filePath}: valid syntax, structure preserved, trackers consent-gated.`);\n } else {\n rejectedPatches.push(patch);\n comments.push(`✖ [REJECTED] ${patch.filePath}:\\n ${errors.join(\"\\n \")}`);\n }\n }\n\n // Optional non-blocking LLM peer review (all-or-nothing gate: any rejected patch fails the verdict,\n // so no partially-fixed state is ever written).\n if (config.apiKey && rejectedPatches.length === 0) {\n comments.push(...(await this.runLlmPeerReview(approvedPatches, config)));\n }\n\n return {\n passed: rejectedPatches.length === 0 && approvedPatches.length > 0,\n score: Math.round((approvedPatches.length / patches.length) * 100),\n comments: [...comments, LEGAL_DISCLAIMER],\n approvedPatches,\n rejectedPatches,\n };\n }\n\n private reviewPatch(patch: FilePatch, report: LeakReport): string[] {\n const errors: string[] = [];\n const content = patch.patchedContent;\n const isHtml = HTML_EXT.test(patch.filePath);\n const isJs = JS_EXT.test(patch.filePath);\n\n if (!content || content.trim().length === 0) {\n return [`[Syntax] Patched content is empty.`];\n }\n\n if (patch.originalContent === undefined) {\n errors.push(\"[Integrity] originalContent missing; cannot verify the patch against the original.\");\n } else {\n if (patch.originalContent === content) {\n errors.push(\"[Compliance] Patch is identical to the original file; nothing was fixed.\");\n }\n const origLines = patch.originalContent.split(\"\\n\").length;\n const newLines = content.split(\"\\n\").length;\n if (origLines > 10 && newLines < origLines * 0.5) {\n errors.push(\n `[Regression] File shrank from ${origLines} to ${newLines} lines (suspected code loss).`\n );\n }\n if (isHtml) {\n for (const tag of [\"</body>\", \"</html>\"]) {\n if (patch.originalContent.includes(tag) && !content.includes(tag)) {\n errors.push(`[Integrity] Essential closing tag '${tag}' was removed.`);\n }\n }\n }\n }\n\n if (isHtml) {\n // Strip script bodies first so '<script' inside strings (e.g. document.write) is not counted.\n const markup = content.replace(/(<script\\b[^>]*>)[\\s\\S]*?(<\\/script\\s*>)/gi, \"$1$2\");\n const opens = (markup.match(/<script\\b[^>]*>/gi) ?? []).length;\n const closes = (markup.match(/<\\/script\\s*>/gi) ?? []).length;\n if (opens !== closes) {\n errors.push(`[Syntax] Unbalanced <script> tags: ${opens} opened vs ${closes} closed.`);\n }\n extractScripts(content).forEach((b, i) => {\n if (isExecutableJs(b.attrs) && b.body.trim()) {\n errors.push(...syntaxErrors(b.body, `inline-script-${i + 1}.js`));\n }\n });\n } else if (isJs) {\n errors.push(...syntaxErrors(content, patch.filePath));\n }\n\n errors.push(...this.checkPrivacyCompliance(patch, report));\n return errors;\n }\n\n /**\n * For every tracker family that leaked, each script block / source file that references it must be gated:\n * blocked via type=\"text/plain\" / data-cookiecategory, or guarded by real (non-comment) consent code.\n */\n private checkPrivacyCompliance(patch: FilePatch, report: LeakReport): string[] {\n const errors: string[] = [];\n const markers = new Set<TrackerMarker>();\n for (const v of report.violations) {\n for (const m of TRACKER_MARKERS) {\n if (m.match(v.trackerName)) markers.add(m);\n }\n }\n if (markers.size === 0) return errors;\n\n const isHtml = HTML_EXT.test(patch.filePath);\n const isJs = JS_EXT.test(patch.filePath);\n const units: { attrs: string; code: string; label: string; fileName: string }[] = isHtml\n ? extractScripts(patch.patchedContent).map((b, i) => ({\n attrs: b.attrs,\n code: b.body,\n label: `<script> #${i + 1}`,\n fileName: `inline-script-${i + 1}.js`,\n }))\n : [{ attrs: \"\", code: patch.patchedContent, label: \"file\", fileName: patch.filePath }];\n\n for (const marker of markers) {\n for (const u of units) {\n if (isBlockedByType(u.attrs)) continue; // inert until the CMP re-enables it\n\n // External tag referencing a tracker (src / data-src) that is still executable.\n if (marker.code.test(u.attrs)) {\n errors.push(`[Compliance] ${u.label} loads a tracker without type=\"text/plain\" (still executes before consent).`);\n continue;\n }\n\n const executable = isHtml ? isExecutableJs(u.attrs) && u.code.trim().length > 0 : true;\n if (!executable) continue;\n\n if (isHtml || isJs) {\n for (const line of findUnguardedTrackerUsages(u.code, u.fileName, marker.code)) {\n errors.push(`[Compliance] ${u.label} line ${line}: tracker usage is not inside/after a consent guard.`);\n }\n } else {\n // Non-parsable formats (e.g. .vue/.svelte): weaker heuristic, any real consent code in the file.\n const code = stripComments(u.code);\n if (marker.code.test(code) && !CONSENT_GUARD.test(code)) {\n errors.push(`[Compliance] ${u.label} references a tracker without any consent guard (heuristic).`);\n }\n }\n }\n }\n return errors;\n }\n\n private async runLlmPeerReview(patches: FilePatch[], config: GateConfig): Promise<string[]> {\n if (config.llmProvider !== \"openai\") return [];\n try {\n const response = await fetch(\"https://api.openai.com/v1/chat/completions\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${config.apiKey}`,\n },\n signal: AbortSignal.timeout(20000),\n body: JSON.stringify({\n model: config.llmModel || \"gpt-4o\",\n messages: [\n {\n role: \"system\",\n content:\n \"You are an expert Code Reviewer. Inspect the provided code patches for privacy fixes. Respond in 1 concise sentence verifying code safety.\",\n },\n {\n role: \"user\",\n content: `Review these patches:\\n${patches.map((p) => p.patchedContent).join(\"\\n---\\n\")}`,\n },\n ],\n temperature: 0.1,\n max_tokens: 150,\n }),\n });\n if (response.ok) {\n const json = (await response.json()) as { choices?: { message?: { content?: string } }[] };\n const reply = json.choices?.[0]?.message?.content?.trim();\n if (reply) return [`🤖 [LLM Peer Reviewer]: ${reply}`];\n }\n } catch {\n // LLM peer review is a non-blocking enhancement\n }\n return [];\n }\n}\n","/**\n * Legal positioning for every user-facing surface (CLI, PR body, review).\n * CPCG is a technical aid — never a substitute for legal advice.\n */\nexport const LEGAL_DISCLAIMER =\n \"⚠️ **Hinweis / Disclaimer:** CPCG ist ein technisches Hilfsmittel zur \" +\n \"Unterstützung bei der Implementierung von Consent-Lösungen — **keine Rechtsberatung** \" +\n \"und keine Garantie für DSGVO-/TTDSG-Konformität. Bitte lassen Sie die endgültige \" +\n \"Umsetzung anwaltlich prüfen. / CPCG is a technical aid, **not legal advice** and no \" +\n \"guarantee of GDPR/ePrivacy compliance. Have the final implementation reviewed by counsel.\";\n\nexport function withDisclaimer(body: string): string {\n return `${body}\\n\\n---\\n${LEGAL_DISCLAIMER}`;\n}\n","import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport {\n FilePatch,\n GateConfig,\n LeakReport,\n PullRequestResult,\n ReviewVerdict,\n} from \"../../types/index.js\";\nimport { LEGAL_DISCLAIMER } from \"../legal/disclaimer.js\";\n\nconst execFileAsync = promisify(execFile);\n\nconst BRANCH_PREFIX_RE = /^[A-Za-z0-9._/-]+$/;\n\nexport function validateBranchPrefix(prefix: string): void {\n if (\n !BRANCH_PREFIX_RE.test(prefix) ||\n prefix.includes(\"..\") ||\n prefix.startsWith(\"-\") ||\n prefix.startsWith(\"/\") ||\n prefix.endsWith(\"/\") ||\n prefix.endsWith(\".lock\") ||\n prefix.includes(\"//\")\n ) {\n throw new Error(`Invalid branch prefix '${prefix}'. Allowed: letters, digits, '.', '_', '/', '-'.`);\n }\n}\n\n/** Removes credentials (URL userinfo and the configured token) from text before logging or reporting. */\nexport function redactSecrets(text: string, token?: string): string {\n let out = text.replace(/\\/\\/[^@/\\s]+@/g, \"//***@\");\n if (token) out = out.split(token).join(\"***\");\n return out;\n}\n\nexport function parseGitHubRepo(url: string): { owner: string; repo: string } | null {\n if (!url) return null;\n const m = url\n .trim()\n .match(/^(?:https?:\\/\\/(?:[^@/]+@)?github\\.com\\/|ssh:\\/\\/git@github\\.com\\/|git@github\\.com:)([^/]+)\\/([^/]+?)(?:\\.git)?\\/?$/i);\n return m ? { owner: m[1], repo: m[2] } : null;\n}\n\nfunction escapeCell(s: string): string {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\r?\\n/g, \" \");\n}\n\nexport { escapeCell };\n\n/** Git-Auth mit Token (CI ohne vorinstallierte Credentials). */\nfunction tokenArgs(token?: string): string[] {\n if (!token) return [];\n const basic = Buffer.from(`x-access-token:${token}`).toString(\"base64\");\n return [\"-c\", `http.extraheader=AUTHORIZATION: basic ${basic}`];\n}\n\nexport class PullRequestEngine {\n private async git(args: string[], token?: string): Promise<string> {\n try {\n const { stdout } = await execFileAsync(\"git\", args, {\n maxBuffer: 10 * 1024 * 1024,\n env: process.env,\n });\n return stdout.trim();\n } catch (err) {\n const e = err as { stderr?: string; message?: string };\n throw new Error(\n `git ${args[0]} failed: ${redactSecrets((e.stderr || e.message || String(err)).trim(), token)}`\n );\n }\n }\n\n /**\n * Creates a fix branch, commits only the given files, pushes and opens a PR when a remote + token exist.\n * Always returns to the starting branch. Throws on any git/API failure (caller restores the working tree).\n */\n async createPullRequest(\n patches: FilePatch[],\n report: LeakReport,\n reviewVerdict: ReviewVerdict,\n config: GateConfig\n ): Promise<PullRequestResult> {\n validateBranchPrefix(config.branchPrefix);\n\n const startBranch = await this.git([\"rev-parse\", \"--abbrev-ref\", \"HEAD\"]);\n if (startBranch === \"HEAD\") {\n throw new Error(\"Detached HEAD: cannot create a fix branch.\");\n }\n\n const branchName = `${config.branchPrefix}-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;\n const title = `fix(privacy): remediate ${report.totalViolations} unauthorized tracker leak(s)`;\n const body = this.buildPrDescription(report, reviewVerdict, patches, config);\n const files = patches.map((p) => p.filePath);\n\n await this.git([\"checkout\", \"-b\", branchName]);\n let keepBranch = false;\n try {\n await this.git([\"add\", \"--\", ...files]);\n await this.git([\"commit\", \"-m\", title, \"--\", ...files]);\n\n let remoteUrl = \"\";\n try {\n remoteUrl = await this.git([\"config\", \"--get\", \"remote.origin.url\"]);\n } catch {\n // no origin configured\n }\n const repo = parseGitHubRepo(remoteUrl);\n\n if (!config.githubToken || !repo) {\n keepBranch = true;\n return { branchName, title, body, simulated: true };\n }\n\n const baseBranch = config.baseBranch || (await this.resolveBaseBranch(startBranch));\n await this.git([...tokenArgs(config.githubToken), \"push\", \"-u\", \"origin\", branchName], config.githubToken);\n keepBranch = true; // pushed: never delete a branch that exists on the remote\n\n const res = await fetch(`https://api.github.com/repos/${repo.owner}/${repo.repo}/pulls`, {\n method: \"POST\",\n headers: {\n Accept: \"application/vnd.github+json\",\n Authorization: `Bearer ${config.githubToken}`,\n \"Content-Type\": \"application/json\",\n },\n signal: AbortSignal.timeout(15000),\n body: JSON.stringify({ title, head: branchName, base: baseBranch, body }),\n });\n\n if (!res.ok) {\n const text = redactSecrets(await res.text().catch(() => \"\"), config.githubToken);\n throw new Error(`GitHub PR creation failed (HTTP ${res.status}): ${text.slice(0, 500)}`);\n }\n\n const pr = (await res.json()) as { number: number; html_url: string };\n return { branchName, title, body, prNumber: pr.number, prUrl: pr.html_url, simulated: false };\n } finally {\n if (!keepBranch) {\n // Failure before anything was published: unstage so the index does not carry the patch.\n await this.git([\"reset\", \"-q\", \"--\", ...files]).catch(() => undefined);\n }\n // Leave the user's branch untouched; the fix lives on the PR branch.\n await this.git([\"checkout\", startBranch]).catch(() => undefined);\n if (!keepBranch) {\n await this.git([\"branch\", \"-D\", branchName]).catch(() => undefined);\n }\n }\n }\n\n private async resolveBaseBranch(fallback: string): Promise<string> {\n try {\n const ref = await this.git([\"symbolic-ref\", \"--short\", \"refs/remotes/origin/HEAD\"]);\n return ref.replace(/^origin\\//, \"\") || fallback;\n } catch {\n return fallback;\n }\n }\n\n buildPrDescription(\n report: LeakReport,\n reviewVerdict: ReviewVerdict,\n patches: FilePatch[],\n config: GateConfig\n ): string {\n const lines: string[] = [\n \"## 🛡️ Cuonztech Privacy Chaos Gate (CPCG) - Auto-Remediation PR\",\n \"\",\n `This Pull Request was automatically generated to remediate **${report.totalViolations} unauthorized tracker leak(s)** detected during Privacy Chaos Engineering tests on \\`${config.targetUrl}\\`.`,\n \"\",\n \"### 🔍 Review Agent Verdict\",\n `- **Score:** \\`${reviewVerdict.score}/100\\``,\n `- **Status:** ${reviewVerdict.passed ? \"✅ **APPROVED (No defects detected)**\" : \"⚠️ **REVIEW COMMENTS**\"}`,\n ];\n for (const comment of reviewVerdict.comments) {\n lines.push(` * ${comment.replace(/\\r?\\n\\s*/g, \" \")}`);\n }\n\n lines.push(\"\", \"### 🚨 Fixed Privacy Violations\");\n lines.push(\"| Scenario | Tracker | Category | Intercepted Request |\");\n lines.push(\"| :--- | :--- | :--- | :--- |\");\n for (const v of report.violations) {\n lines.push(\n `| \\`${escapeCell(v.scenario)}\\` | **${escapeCell(v.trackerName)}** | \\`${escapeCell(v.trackerCategory)}\\` | \\`${escapeCell(v.requestUrl)}\\` |`\n );\n }\n\n lines.push(\"\", \"### 📁 Modified Files\");\n for (const patch of patches) {\n lines.push(`* **\\`${patch.filePath}\\`**: ${patch.explanation}`);\n }\n\n lines.push(\n \"\",\n \"### 🧪 Verification\",\n \"Run the Privacy Chaos Gate locally to verify all chaos scenarios pass:\",\n \"```bash\",\n `npx @cuonztech/privacy-chaos-gate --url \"${config.targetUrl}\"`,\n \"```\",\n \"\",\n \"---\",\n \"_Generated by Cuonztech Privacy Chaos Gate Auto-Remediation Engine & Review Agent._\"\n );\n lines.push(\"\", LEGAL_DISCLAIMER);\n return lines.join(\"\\n\");\n }\n}\n","/**\n * Jurisdiktions-Profile für CPCG.\n * Das Tool bewertet Pre-Consent-Tracking je Rechtsraum — KEINE Rechtsberatung.\n */\nexport type Jurisdiction = \"CH\" | \"EU\" | \"UK\" | \"US-CA\" | \"BR\" | \"ROW\";\n\nexport interface JurisdictionProfile {\n code: Jurisdiction;\n label: string;\n /** Kerndokumente / Frameworks im Report */\n frameworks: string[];\n /** Ist vorheriges Opt-In für nicht-essenzielles Tracking erforderlich? */\n priorOptInRequired: boolean;\n /** Google Consent Mode v2 erforderlich / empfohlen? */\n consentModeV2: \"required\" | \"recommended\" | \"optional\";\n /** Kurztext für den Kunden-Report */\n summary: string;\n /** Formulierung ohne Rechtsberatung zu sein */\n note: string;\n}\n\nexport const JURISDICTIONS: Record<Jurisdiction, JurisdictionProfile> = {\n CH: {\n code: \"CH\",\n label: \"Schweiz\",\n frameworks: [\"revDSG (nDSG)\", \"FDPIC-Richtlinien\", \"UWG (irreführende Praktiken)\"],\n priorOptInRequired: true,\n consentModeV2: \"recommended\",\n summary:\n \"Schweizer Datenschutz (revDSG) ist prinzipienbasiert. Der EDÖB beschreibt insbesondere \" +\n \"Konstellationen personalisierter Werbung (Profiling, Marketing-Tracker), in denen eine \" +\n \"Einwilligung erforderlich ist. Für übriges Tracking gelten Transparenz- und \" +\n \"Informationspflichten; die Grenzen sind einzelfallabhängig. Da viele CH-Seiten auch \" +\n \"EU-Nutzer erreichen, empfiehlt sich häufig die strengere EU-Linie.\",\n note:\n \"Einordnung nach revDSG und EDÖB-Cookie-Guidance. Ob Einwilligung erforderlich ist, hängt \" +\n \"vom Zweck der Verarbeitung ab (personalisierte Werbung: ja). Keine Rechtsberatung — \" +\n \"bei EU-Zielgruppe zusätzlich EU-Profil nutzen.\",\n },\n EU: {\n code: \"EU\",\n label: \"Europäische Union\",\n frameworks: [\"GDPR/DSGVO\", \"ePrivacy-Richtlinie\", \"TTDSG (DE)\", \"Google Consent Mode v2 (EEA)\"],\n priorOptInRequired: true,\n consentModeV2: \"required\",\n summary:\n \"In der EU gilt für nicht-essenzielle Tracker (Analytics, Marketing, Hotjar, TikTok …) \" +\n \"grundsätzlich vorheriges Opt-In (GDPR, ePrivacy, TTDSG). Ein vor der Einwilligung \" +\n \"beobachteter Request ist ein starker Hinweis — ob ein Rechtsverstoss vorliegt, hängt \" +\n \"vom Zweck, der Technologie und dem dokumentierten Consent-Zustand ab und ist im \" +\n \"Einzelfall zu prüfen. Google Consent Mode v2 ist für Google-Produkte im EEA \" +\n \"vorgeschrieben; er ist eine technische Implementierung, keine Rechtsgrundlage.\",\n note:\n \"Technischer Befund mit regulatorischem Kontext, keine Rechtsberatung. Verbindliche \" +\n \"Einstufung durch Datenschutzbeauftragte/n oder Anwalt/Anwältin.\",\n },\n UK: {\n code: \"UK\",\n label: \"Vereinigtes Königreich\",\n frameworks: [\"UK GDPR\", \"PECR\"],\n priorOptInRequired: true,\n consentModeV2: \"required\",\n summary:\n \"UK GDPR + PECR entsprechen der EU-ePrivacy-Linie: Opt-In vor nicht-essenziellem Tracking. \" +\n \"Auch hier ist ein beobachteter Request ein Hinweis — die rechtliche Einstufung erfolgt im Einzelfall.\",\n note: \"Bewertung nach UK GDPR/PECR. Keine Rechtsberatung.\",\n },\n \"US-CA\": {\n code: \"US-CA\",\n label: \"USA — Kalifornien (CCPA/CPRA)\",\n frameworks: [\"CCPA/CPRA\", \"Do Not Sell / Share\", \"Global Privacy Control (GPC)\", \"Opt-out model\"],\n priorOptInRequired: false,\n consentModeV2: \"recommended\",\n summary:\n \"CCPA/CPRA sind primär opt-out-basiert (Do Not Sell or Share). Pre-Consent-Tracking ist \" +\n \"nicht per se verboten, verlangt aber klare Opt-out-Mechanismen und Offenlegung. \" +\n \"Diese Bewertung gilt als unvollständig, solange Sale/Sharing-Opt-out und das Global \" +\n \"Privacy Control (GPC) nicht geprüft sind — erfasste Unternehmen müssen GPC als \" +\n \"wirksamen Opt-out berücksichtigen.\",\n note:\n \"Technische Beobachtung, keine Rechtsberatung. Ohne GPC- und Sale/Sharing-Prüfung \" +\n \"keine abschliessende CCPA-Bewertung. Für gemischte CA/EU-Traffic EU-Profil anwenden.\",\n },\n BR: {\n code: \"BR\",\n label: \"Brasilien (LGPD)\",\n frameworks: [\"LGPD\"],\n priorOptInRequired: true,\n consentModeV2: \"recommended\",\n summary:\n \"LGPD verlangt eine Rechtsgrundlage; Consent ist für Marketing-Tracking üblich und sicher. \" +\n \"Die konkrete Einstufung eines Pre-Consent-Requests erfordert die Prüfung von Zweck und Technologie.\",\n note: \"Bewertung nach LGPD-Praxis. Keine Rechtsberatung.\",\n },\n ROW: {\n code: \"ROW\",\n label: \"Rest der Welt\",\n frameworks: [\"Landesspezifisch (z. B. PIPEDA, PDPA, APPs)\"],\n priorOptInRequired: false,\n consentModeV2: \"recommended\",\n summary:\n \"Nicht bewertet — länderspezifische Prüfung erforderlich. CPCG dokumentiert \" +\n \"Pre-Consent-Tracking hier neutral als technischen Befund. Für konkrete Zielländer \" +\n \"gelten unterschiedliche Regeln (PIPEDA, PDPA, APPs, u. a.), die lokal zu prüfen sind.\",\n note:\n \"Keine globale Opt-in-/Opt-out-Regel unterstellt. Für konkrete Märkte Juristin/Jurist beiziehen.\",\n },\n};\n\nexport function resolveJurisdiction(code?: string): JurisdictionProfile {\n const key = (code ?? \"CH\").toUpperCase().replace(\"_\", \"-\");\n if (key in JURISDICTIONS) return JURISDICTIONS[key as Jurisdiction];\n return JURISDICTIONS.ROW;\n}\n\n/**\n * Schweregrad eines Pre-Consent-Leaks je Rechtsraum.\n * Die technischen Fakten ändern sich nicht — die rechtliche Einordnung schon.\n * Ein erkannter Request ist KEIN bewiesener Rechtsverstoss: Zweck, Technologie\n * und Consent-Zustand gehören zur Bewertung.\n */\nexport type LeakSeverity = \"P0\" | \"P1\" | \"P2\";\n\nexport function severityForPreConsentLeak(profile: JurisdictionProfile): {\n severity: LeakSeverity;\n framing: string;\n} {\n if (profile.code === \"ROW\") {\n return {\n severity: \"P2\",\n framing:\n \"Nicht bewertet — länderspezifische Prüfung erforderlich. Reiner technischer Befund.\",\n };\n }\n if (profile.priorOptInRequired && profile.consentModeV2 === \"required\") {\n return {\n severity: \"P0\",\n framing:\n \"Opt-In-Pflicht für nicht-essenzielle Tracker. Ein vor der Einwilligung beobachteter \" +\n \"Request ist ein schwerwiegender Compliance-Hinweis — die rechtliche Einstufung als \" +\n \"Verstoß erfordert die Prüfung von Zweck, Technologie und Consent-Zustand.\",\n };\n }\n if (profile.priorOptInRequired) {\n return {\n severity: \"P1\",\n framing:\n \"In diesem Rechtsraum gilt für personalisierte Werbung in der Praxis häufig eine \" +\n \"Einwilligungslösung (vergleichbare Aufsichtspraxis); Pre-Consent-Tracking ist ein Risiko, \" +\n \"nicht zwingend ein klarer Rechtsbruch. Zweck und Technologie mit einbeziehen.\",\n };\n }\n return {\n severity: \"P2\",\n framing:\n \"Opt-out-Modell: technischer Befund ohne per-se-Verstoß. Offenlegung, Opt-out-Wege und \" +\n \"GPC-Unterstützung prüfen.\",\n };\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { EvidenceRecord, LeakReport } from \"../../types/index.js\";\nimport {\n JURISDICTIONS,\n severityForPreConsentLeak,\n type Jurisdiction,\n} from \"../legal/jurisdictions.js\";\n\n/**\n * Kunden-Report aus LeakReport + Evidence.\n * Status-Tabelle je Szenario: bestanden / auffällig / nicht prüfbar.\n * Keine echten Kundennamen einbauen — der Inhalt kommt aus dem Scan.\n */\nexport interface EvidenceMarkdownOptions {\n demo?: boolean;\n}\n\n/** Status-Lesart für beide Renderer — eine Quelle, kein Drift. */\nexport function statusLabelOf(s: EvidenceRecord[\"status\"]): string {\n return s === \"passed\"\n ? \"bestanden\"\n : s === \"suspicious\"\n ? \"auffällig\"\n : s === \"not-applicable\"\n ? \"nicht anwendbar\"\n : \"nicht prüfbar\";\n}\n\n/** Zählung und Gate-Text — von Markdown und HTML gemeinsam genutzt. */\nexport interface ReportFacts {\n evidenceCount: number;\n passed: number;\n flagged: number;\n uncheckable: number;\n notApplicable: number;\n incomplete: number;\n findings: number;\n observedCount: number;\n gate: \"PASS\" | \"BLOCKED\";\n findingsText: string;\n gateDisclaimer: string;\n problemCount: number;\n problemsText: string;\n}\n\n/** Konkrete Code-Lösung je verletzter Regel — nur für belegte Befunde. */\nexport interface CodeSolution {\n ruleId: string;\n title: string;\n lang: \"html\" | \"js\";\n code: string;\n}\n\nconst CODE_SOLUTIONS: Record<string, Omit<CodeSolution, \"ruleId\">> = {\n \"pre-consent-tracking\": {\n title: \"Tracker erst nach Einwilligung laden (Defer-Muster)\",\n lang: \"html\",\n code: `<!-- Vorher: feuert sofort im <head> -->\n<script async src=\"https://www.googletagmanager.com/gtag/js?id=G-XXXX\"></script>\n<script>\n window.dataLayer = window.dataLayer || [];\n function gtag(){ dataLayer.push(arguments); }\n gtag('js', new Date());\n gtag('config', 'G-XXXX');\n</script>\n\n<!-- Nachher: Blockiert bis die CMP die Kategorie freigibt -->\n<script type=\"text/plain\" data-cookiecategory=\"analytics\"\n data-src=\"https://www.googletagmanager.com/gtag/js?id=G-XXXX\"></script>\n<script type=\"text/plain\" data-cookiecategory=\"analytics\">\n window.dataLayer = window.dataLayer || [];\n function gtag(){ dataLayer.push(arguments); }\n gtag('js', new Date());\n gtag('config', 'G-XXXX');\n</script>\n\n<!-- CMP-Callback: bei Akzeptieren Typ umschreiben und ausführen -->\n<script>\n window.addEventListener('consent-given', (e) => {\n if (!e.detail?.analytics) return;\n document.querySelectorAll('script[data-cookiecategory=\"analytics\"]').forEach((s) => {\n const t = document.createElement('script');\n t.type = 'text/javascript';\n if (s.dataset.src) t.src = s.dataset.src;\n else t.text = s.text;\n s.replaceWith(t);\n });\n });\n</script>`,\n },\n \"tracking-without-consent\": {\n title: \"Auch nach Widerruf-Reset keine Tracker ohne erneute Zustimmung\",\n lang: \"html\",\n code: `<!-- Consent-Status ist die einzige Eintrittskontrolle -->\n<script>\n function trackerAllowed(category) {\n const c = window.__consent; // von der CMP gesetzt\n return !!(c && c[category] === true);\n }\n\n // Kein direkter Aufruf von gtag/pixel/fbq ohne diesen Check.\n if (trackerAllowed('analytics')) {\n gtag('config', 'G-XXXX');\n }\n</script>`,\n },\n \"pre-consent-embed\": {\n title: \"Externe Embeds hinter eine Consent-Fassade legen\",\n lang: \"html\",\n code: `<!-- Vorher: iframe lädt Drittinhalte ohne Einwilligung -->\n<iframe src=\"https://www.youtube-nocookie.com/embed/VIDEO_ID\"></iframe>\n\n<!-- Nachher: Fassade, iFrame erst nach Klick -->\n<div class=\"embed-gate\" data-embed=\"https://www.youtube-nocookie.com/embed/VIDEO_ID\">\n <button type=\"button\" class=\"embed-gate__load\">Video laden (setzt Cookies von YouTube)</button>\n</div>\n<script>\n document.querySelectorAll('.embed-gate').forEach((gate) => {\n gate.querySelector('button').addEventListener('click', () => {\n const src = gate.dataset.embed;\n gate.innerHTML = '';\n const iframe = document.createElement('iframe');\n iframe.src = src;\n iframe.allow = 'accelerometer; autoplay; encrypted-media; picture-in-picture';\n iframe.allowFullscreen = true;\n gate.appendChild(iframe);\n });\n });\n</script>`,\n },\n \"tracking-after-revoke\": {\n title: \"Nach Widerruf: Tracker stoppen und Rest-IDs bereinigen\",\n lang: \"js\",\n code: `// Schematisches Muster — an die eigene CMP/Tracker anpassen.\n// In den Revoke-Handler der CMP einhängen.\nfunction onConsentRevoked() {\n // 1. Laufende Tracker abschalten\n window['ga-disable-G-XXXX'] = true;\n if (window.gtag) {\n gtag('consent', 'update', {\n ad_storage: 'denied',\n analytics_storage: 'denied',\n ad_user_data: 'denied',\n ad_personalization: 'denied',\n });\n }\n\n // 2. Tracker-Cookies löschen (nur IDs, die der Scan als Residual gemeldet hat)\n const names = ['_ga', '_gid', '_gat', '_fbp', '_fbc', 'fr'];\n for (const name of names) {\n for (const path of ['/', '/blog', '/shop']) {\n document.cookie = name + '=; Max-Age=0; path=' + path + '; SameSite=Lax';\n document.cookie = name + '=; Max-Age=0; path=' + path +\n '; domain=.' + location.hostname.replace(/^www\\\\./, '') + '; SameSite=Lax';\n }\n }\n\n // 3. Tracker-Residual aus localStorage/sessionStorage entfernen.\n // WICHTIG: CMP-Entscheidungsspeicher (OptanonConsent, CookieConsent,\n // usercentrics-consent) NICHT löschen — dort steht die Ablehnung.\n const residualPrefixes = ['_ga', '_gid', '_gat', '_fbp', '_fbc'];\n for (const store of [localStorage, sessionStorage]) {\n for (const key of Object.keys(store)) {\n if (residualPrefixes.some((p) => key === p || key.startsWith(p + '.'))) {\n store.removeItem(key);\n }\n }\n }\n}`,\n },\n \"tracking-after-deny\": {\n title: \"Ablehnung respektieren: kein Tracking ohne Opt-In\",\n lang: \"js\",\n code: `// CMP: Choice speichern und Tracker erst bei explizitem Accept aktivieren\nfunction onConsentChoice(choice) {\n // choice = { analytics: boolean, marketing: boolean }\n if (!choice.analytics) {\n window['ga-disable-G-XXXX'] = true;\n window.gtag?.('consent', 'update', { analytics_storage: 'denied' });\n return; // keine Analytics-Requests\n }\n window['ga-disable-G-XXXX'] = false;\n window.gtag?.('consent', 'update', { analytics_storage: 'granted' });\n gtag('config', 'G-XXXX');\n}`,\n },\n \"tracking-declined-category\": {\n title: \"Kategorie-Selektivität: abgelehnte Kategorien bleiben blockiert\",\n lang: \"js\",\n code: `// CMP gibt Kategorie-Flags zurück — nur freigegebene Kategorien starten Tracker\nfunction activateFor(consent) {\n if (consent.analytics) {\n loadScript('https://www.googletagmanager.com/gtag/js?id=G-XXXX');\n gtag('config', 'G-XXXX');\n }\n if (consent.marketing) {\n // Meta Pixel, LinkedIn Insight etc. erst hier\n !function(f,b,e,v,n,t,s){/* fbq init */}(window,document,'script');\n }\n // Kategorie \"functional\" lädt keine Tracker\n}`,\n },\n \"duplicate-events\": {\n title: \"Doppelte Analytics-Einträge vermeiden (ein Tag-Manager)\",\n lang: \"html\",\n code: `<!-- Vorher: Plugin UND GTM senden beide page_view -->\n<script async src=\"https://www.googletagmanager.com/gtag/js?id=G-XXXX\"></script>\n<script>gtag('config', 'G-XXXX');</script>\n<!-- PLUS GTM-Container, der dasselbe Event noch einmal sendet -->\n\n<!-- Nachher: genau eine Quelle. Entweder gtag ODER GTM — nicht beide. -->\n<!-- Variante A: nur gtag -->\n<script async src=\"https://www.googletagmanager.com/gtag/js?id=G-XXXX\"></script>\n<script>\n gtag('js', new Date());\n gtag('config', 'G-XXXX'); // sendet page_view genau einmal\n</script>\n\n<!-- Variante B: nur GTM-Container (dataLayer statt zusätzlichem gtag-config) -->\n<script>\n window.dataLayer = window.dataLayer || [];\n window.dataLayer.push({ event: 'page_view' });\n</script>`,\n },\n \"consent-mode-mismatch\": {\n title: \"Google Consent Mode v2 konsistent setzen\",\n lang: \"js\",\n code: `// Schematisches Muster — vor jedem Google-Tag ausführen.\n// Default: alles denied — BEVOR irgendein Google-Tag lädt.\nwindow.dataLayer = window.dataLayer || [];\nfunction gtag(){ dataLayer.push(arguments); }\ngtag('js', new Date());\n\ngtag('consent', 'default', {\n ad_storage: 'denied',\n ad_user_data: 'denied',\n ad_personalization: 'denied',\n analytics_storage: 'denied',\n wait_for_update: 500,\n});\n\n// CMP-Update: nur die tatsächlich erteilten Kategorien auf granted\nfunction onConsentUpdate(consent) {\n gtag('consent', 'update', {\n analytics_storage: consent.analytics ? 'granted' : 'denied',\n ad_storage: consent.marketing ? 'granted' : 'denied',\n ad_user_data: consent.marketing ? 'granted' : 'denied',\n ad_personalization: consent.marketing ? 'granted' : 'denied',\n });\n}`,\n },\n};\n\n/** Nur Regeln mit belegtem Befund bekommen eine Code-Lösung. */\nexport function codeSolutionsFor(report: LeakReport): CodeSolution[] {\n const ruleIds = [...new Set(report.violations.map((v) => v.ruleId ?? \"pre-consent-tracking\"))];\n const out: CodeSolution[] = [];\n for (const id of ruleIds) {\n const sol = CODE_SOLUTIONS[id];\n if (sol) out.push({ ruleId: id, ...sol });\n }\n return out;\n}\n\nexport function deriveReportFacts(report: LeakReport): ReportFacts {\n const evidence = report.evidence ?? [];\n const passed = evidence.filter((e) => e.status === \"passed\").length;\n const flagged = evidence.filter((e) => e.status === \"suspicious\").length;\n const uncheckable = evidence.filter((e) => e.status === \"not-checkable\").length;\n const notApplicable = evidence.filter((e) => e.status === \"not-applicable\").length;\n let observedCount = 0;\n for (const e of evidence) {\n for (const r of e.requestTimeline) {\n if (r.trackerName) observedCount++;\n }\n }\n const findings = report.totalViolations;\n return {\n evidenceCount: evidence.length,\n passed,\n flagged,\n uncheckable,\n notApplicable,\n incomplete: uncheckable + notApplicable,\n findings,\n observedCount,\n gate: findings === 0 ? \"PASS\" : \"BLOCKED\",\n findingsText: findingsCountText(findings),\n gateDisclaimer: \"Eine rechtliche Gesamtbewertung erfolgt nicht.\",\n problemCount: groupFindings(report.violations ?? []).length,\n problemsText: problemsTextOf(groupFindings(report.violations ?? []).length),\n };\n}\n\n/** 1 Befund-Zeile / N Befund-Zeilen — nie «Befund-Zeile(n)». */\nexport function findingsCountText(n: number): string {\n return n === 1 ? \"1 dokumentierte Befund-Zeile\" : `${n} dokumentierte Befund-Zeilen`;\n}\n\n/** Kundennutzen: Befundgruppen statt Request-Zeilen. */\nexport function problemsTextOf(n: number): string {\n return n === 0\n ? \"Keine offenen Befundgruppen\"\n : n === 1\n ? \"1 Befundgruppe\"\n : `${n} Befundgruppen`;\n}\n\n/** Gruppiert Befunde zu Befundgruppen (Regel + Tracker). */\nexport function groupFindings(violations: { ruleId?: string; trackerName: string }[]): {\n key: string;\n ruleId: string;\n trackerName: string;\n count: number;\n}[] {\n const map = new Map<string, { key: string; ruleId: string; trackerName: string; count: number }>();\n for (const v of violations) {\n const ruleId = v.ruleId ?? \"pre-consent-tracking\";\n const key = `${ruleId}|${v.trackerName}`;\n const cur = map.get(key);\n if (cur) cur.count++;\n else map.set(key, { key, ruleId, trackerName: v.trackerName, count: 1 });\n }\n return [...map.values()].sort((a, b) => b.count - a.count);\n}\n\n/** Zähltext: Requests, nicht vage «×». */\nexport function reproductionText(count: number): string {\n return count === 1 ? \"1 Request\" : `${count} Requests`;\n}\n\nexport function buildEvidenceMarkdown(\n report: LeakReport,\n title = \"Evidence Report\",\n options: EvidenceMarkdownOptions = {}\n): string {\n const evidence = report.evidence ?? [];\n const demoLine = options.demo\n ? \"> **Demo-Report** · synthetische Testdaten — keine realen Kundendaten.\\n\\n\"\n : \"\";\n const facts = deriveReportFacts(report);\n const icon = statusLabelOf;\n\n const lines: string[] = [\n `# CuonzTech Privacy Chaos Gate — ${title}`,\n \"\",\n `**Ziel:** \\`${report.targetUrl}\\` `,\n `**Scan:** ${report.scannedAt} `,\n `**Technisches Gate:** ${facts.gate} · ${facts.findingsText} · ${facts.gateDisclaimer}`,\n \"\",\n \"> **Hinweis:** Technisches Hilfsmittel, keine Rechtsberatung. / Technical aid, not legal advice.\",\n \"\",\n \"## Szenarien\",\n \"\",\n \"| Szenario | Status | Bemerkung |\",\n \"|----------|--------|-----------|\",\n ];\n\n for (const e of evidence) {\n const note = e.note.replace(/\\|/g, \"\\\\|\").replace(/`/g, \"'\").replace(/\\s*\\n\\s*/g, \" \");\n lines.push(`| \\`${e.scenario}\\` | **${icon(e.status)}** | ${note} |`);\n }\n\n if (report.violations.length > 0) {\n lines.push(\"\", \"## Befunde\", \"\", \"| Szenario | Tracker | Request |\", \"|----------|---------|---------|\");\n for (const v of report.violations) {\n const url = v.requestUrl.slice(0, 80).replace(/\\|/g, \"\\\\|\").replace(/`/g, \"'\");\n lines.push(\n `| \\`${v.scenario}\\` | ${v.trackerName} | \\`${url}\\` |`\n );\n }\n\n const solutions = codeSolutionsFor(report);\n if (solutions.length > 0) {\n lines.push(\"\", \"## Code-Lösungen\", \"\");\n for (const s of solutions) {\n lines.push(`### ${s.title}`, \"\", `\\`${s.ruleId}\\``, \"\", \"```\" + s.lang, s.code, \"```\", \"\");\n }\n }\n }\n\n lines.push(\"\", \"## Beweis\", \"\");\n for (const e of evidence) {\n if (!e.screenshots?.length && !e.screenshotPath) continue;\n lines.push(`### ${e.scenario}`, \"\");\n for (const s of e.screenshots ?? []) {\n lines.push(`- **${s.label}** (${s.at}): \\`evidence/${path.basename(s.path)}\\``);\n }\n if (e.storageAfter?.cookies?.length) {\n lines.push(`- Cookies nachher: ${e.storageAfter.cookies.slice(0, 8).join(\", \")}`);\n }\n if (e.residualAfterRevoke?.length) {\n lines.push(`- Residual nach Widerruf: ${e.residualAfterRevoke.join(\", \")}`);\n }\n lines.push(\"\");\n }\n\n lines.push(\"---\", \"*© CuonzTech · Privacy Chaos Gate*\");\n return lines.join(\"\\n\");\n}\n\nconst esc = (s: string): string =>\n s\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n\nconst statusLabel = statusLabelOf;\n\nconst statusClass = (s: EvidenceRecord[\"status\"]) =>\n s === \"passed\" ? \"ok\" : s === \"suspicious\" ? \"warn\" : \"skip\";\n\nconst fmtTime = (iso: string): string => {\n const d = new Date(iso);\n return isNaN(d.getTime())\n ? iso\n : d.toLocaleString(\"de-CH\", { dateStyle: \"medium\", timeStyle: \"medium\" });\n};\n\nconst fmtDuration = (ms: number): string =>\n ms >= 60000 ? `${Math.round(ms / 60000)} min` : `${(ms / 1000).toFixed(1)} s`;\n\n/** Screenshot einbetten (data-URI) wenn lesbar, sonst relativer Dateiname. */\nfunction shotSrc(p: string): string {\n try {\n const buf = fs.readFileSync(p);\n const ext = path.extname(p).toLowerCase().replace(\".\", \"\");\n const mime = ext === \"jpg\" ? \"jpeg\" : ext === \"jpeg\" ? \"jpeg\" : \"png\";\n return `data:image/${mime};base64,${buf.toString(\"base64\")}`;\n } catch {\n return \"\";\n }\n}\n\nexport interface EvidenceHtmlOptions {\n /** Demo-Lauf mit synthetischen Testdaten klar kennzeichnen */\n demo?: boolean;\n}\n\n/**\n * HTML-Beweisreport im offiziellen CuonzTech-Brand (Terminal-Schwarz, Gold,\n * Cormorant Garamond + Inter). Drei-Zustands-Logik: bestanden / auffällig /\n * nicht prüfbar — nie blind grün.\n *\n * Auswertungslogik: Was der Report behauptet, wird aus dem Scan abgeleitet.\n * - Executive Summary nennt nur ausgeführte Szenarien.\n * - Befunde (Violations) und beobachtete Requests (Timelines) werden getrennt geführt.\n * - Empfehlungen entstehen ausschliesslich aus belegten Befunden.\n * - BLOCKED/PASS bezeichnen ein technisches Gate, keine rechtliche Bewertung.\n */\nexport function buildEvidenceHtml(\n report: LeakReport,\n title = \"Evidence Report\",\n options: EvidenceHtmlOptions = {}\n): string {\n const evidence = report.evidence ?? [];\n const facts = deriveReportFacts(report);\n const passed = facts.passed;\n const flagged = facts.flagged;\n const uncheckable = facts.uncheckable;\n const notApplicable = facts.notApplicable;\n\n // Beobachtete Requests: jede Timeline-Erfassung mit erkanntem Tracker\n // (unabhängig davon, ob sie eine eigene Violation-Row erzeugt hat).\n const observed: { scenario: string; at: string; url: string; trackerName: string; phase: string }[] =\n [];\n for (const e of evidence) {\n for (const r of e.requestTimeline) {\n if (r.trackerName) {\n observed.push({\n scenario: e.scenario,\n at: r.at,\n url: r.url,\n trackerName: r.trackerName,\n phase: r.phase,\n });\n }\n }\n }\n\n const kpis: { label: string; value: string; tone: string }[] = [\n { label: \"Szenarien geprüft\", value: String(evidence.length), tone: \"gold\" },\n { label: \"bestanden\", value: String(passed), tone: \"ok\" },\n { label: \"auffällig\", value: String(flagged), tone: flagged > 0 ? \"warn\" : \"ok\" },\n {\n label: \"nicht prüfbar\",\n value: `${uncheckable + notApplicable}`,\n tone: \"skip\",\n },\n { label: \"Befunde (Leaks)\", value: String(report.totalViolations), tone: report.totalViolations > 0 ? \"warn\" : \"ok\" },\n { label: \"beobachtete Requests\", value: String(observed.length), tone: \"gold\" },\n ];\n\n // --- Gate: technische Freigaberegeln je ruleId, keine Rechtsbewertung ---\n const incomplete = uncheckable + notApplicable;\n const RULE_LABELS: Record<string, string> = {\n \"pre-consent-tracking\": \"Keine Analytics-Requests vor Zustimmung\",\n \"pre-consent-embed\": \"Keine Drittanbieter-Embeds vor Zustimmung\",\n \"tracking-without-consent\": \"Kein Tracking ohne gültige Einwilligung\",\n \"tracking-after-revoke\": \"Kein Tracking nach Widerruf\",\n \"tracking-after-deny\": \"Kein Tracking nach gespeicherter Ablehnung\",\n \"tracking-declined-category\": \"Kein Tracking abgelehnter Kategorien\",\n \"duplicate-events\": \"Keine doppelten Analytics-Events\",\n \"consent-mode-mismatch\": \"Consent-Mode-Zustand deckt sich mit Verhalten\",\n };\n const violatedRules = [...new Set(report.violations.map((v) => v.ruleId ?? \"pre-consent-tracking\"))];\n const ruleText =\n violatedRules.length === 0\n ? \"Die konfigurierten Regeln wurden nicht verletzt.\"\n : `Verletzt: ${violatedRules.map((r) => `«${RULE_LABELS[r] ?? r}»`).join(\", \")}.`;\n const gateClass = report.totalViolations === 0 ? \"\" : \"blocked\";\n const gateTitle = report.totalViolations === 0 ? \"Technisches Gate: PASS\" : \"Technisches Gate: BLOCKED\";\n const gateDetail =\n `${ruleText} ` +\n (incomplete > 0\n ? `${incomplete === 1 ? \"1 Szenario\" : `${incomplete} Szenarien`} konnten nicht abschliessend bewertet werden. `\n : \"\") +\n `Eine rechtliche Gesamtbewertung erfolgt nicht.`;\n\n // --- Executive Summary: nur ausgeführte Szenarien ---\n const ranList = evidence.map((e) => `<code>${esc(e.scenario)}</code>`).join(\", \") || \"—\";\n const summaryHtml = `\n <p>Der Scan führte <strong>${evidence.length === 1 ? \"1 Szenario\" : `${evidence.length} Szenarien`}</strong> aus: ${ranList}.\n Ergebnis: ${passed} bestanden · ${flagged} auffällig · ${uncheckable} nicht prüfbar · ${notApplicable} nicht anwendbar.</p>\n <p>Geführt werden <strong>${esc(findingsCountText(report.totalViolations))}</strong> und\n <strong>${observed.length === 1 ? \"1 beobachteter Request\" : `${observed.length} beobachtete Requests`}</strong> mit erkanntem Tracker\n (Timelines aller Szenarien — auch dort, wo keine Violation-Row entstand).</p>`;\n\n // --- Jurisdictions ---\n const jCodes: Jurisdiction[] = [\"CH\", \"EU\", \"UK\", \"US-CA\", \"BR\", \"ROW\"];\n const hasPreConsentFinding = report.violations.some(\n (v) => (v.ruleId ?? \"pre-consent-tracking\").startsWith(\"pre-consent\") || (v.ruleId ?? \"\") === \"tracking-without-consent\"\n );\n const jCards = jCodes\n .map((code) => {\n const profile = JURISDICTIONS[code];\n const { severity, framing } = severityForPreConsentLeak(profile);\n const tone = severity === \"P0\" ? \"warn\" : severity === \"P1\" ? \"gold\" : \"skip\";\n const framingText = hasPreConsentFinding\n ? framing\n : `Falls ein Pre-Consent-Request beobachtet wird: ${framing} Derzeit kein solcher Befund.`;\n return `<article class=\"jcard\">\n <header><span class=\"sev sev-${tone}\">${severity}</span><h3>${esc(profile.label)}</h3></header>\n <p class=\"jframe\">${esc(framingText)}</p>\n <p class=\"jfw\">${profile.frameworks.map(esc).join(\" · \")}</p>\n </article>`;\n })\n .join(\"\\n\");\n\n // --- Szenario-Karten ---\n const cards = evidence\n .map((e) => {\n const chips = e.actionSequence\n .map((a) => `<span class=\"chip\">${esc(a)}</span>`)\n .join(\"\");\n\n const actionRows = (e.actionTimeline ?? [])\n .slice(0, 12)\n .map(\n (a) => `<tr><td class=\"ts\">${esc(fmtTime(a.at))}</td><td><code>${esc(a.action)}</code></td></tr>`\n )\n .join(\"\");\n\n const reqRows = e.requestTimeline\n .filter((r) => r.trackerName)\n .slice(0, 10)\n .map(\n (r) =>\n `<tr>\n <td class=\"ts\">${esc(fmtTime(r.at))}</td>\n <td>${esc(r.trackerName ?? \"\")}</td>\n <td><span class=\"phase phase-${r.phase.replace(/[^a-z]/g, \"\")}\">${esc(r.phase)}</span></td>\n <td><code>${esc(r.url.slice(0, 90))}</code></td>\n </tr>`\n )\n .join(\"\");\n\n const diff = (before: string[], after: string[], label: string) => {\n const added = after.filter((x) => !before.includes(x));\n const removed = before.filter((x) => !after.includes(x));\n if (!added.length && !removed.length) return \"\";\n return `<p class=\"diff\"><strong>${label}:</strong>\n ${added.map((a) => `<span class=\"add\">+ ${esc(a)}</span>`).join(\" \")}\n ${removed.map((r) => `<span class=\"del\">− ${esc(r)}</span>`).join(\" \")}\n </p>`;\n };\n\n /** Consent-Werte: zeigt erlaubt/abgelehnt, nicht bloss den Schlüssel. */\n const entriesDiff = (\n before: { key: string; value: string }[] | undefined,\n after: { key: string; value: string }[] | undefined,\n label: string\n ) => {\n const b = new Map((before ?? []).map((e) => [e.key, e.value]));\n const a = new Map((after ?? []).map((e) => [e.key, e.value]));\n const rows: string[] = [];\n for (const [key, val] of a) {\n const prev = b.get(key);\n if (prev === undefined) rows.push(`<span class=\"add\">+ ${esc(key)} = ${esc(val)}</span>`);\n else if (prev !== val) rows.push(`<span class=\"add\">~ ${esc(key)} = ${esc(val)}</span> <span class=\"del\">vorher: ${esc(prev)}</span>`);\n }\n for (const [key, val] of b) {\n if (!a.has(key)) rows.push(`<span class=\"del\">− ${esc(key)} = ${esc(val)}</span>`);\n }\n if (!rows.length) return \"\";\n return `<p class=\"diff\"><strong>${label}:</strong> ${rows.join(\" \")}</p>`;\n };\n\n const storageDiff = [\n diff(e.storageBefore.cookies, e.storageAfter.cookies, \"Cookies\"),\n diff(e.storageBefore.localStorageKeys, e.storageAfter.localStorageKeys, \"localStorage\"),\n diff(e.storageBefore.sessionStorageKeys, e.storageAfter.sessionStorageKeys, \"sessionStorage\"),\n entriesDiff(e.storageBefore.localStorageEntries, e.storageAfter.localStorageEntries, \"Consent-Werte\"),\n ].join(\"\");\n\n // Widerruf-Diff: Peak (nach Accept) → Endzustand\n const peakDiff = e.storageAfterAccept\n ? [\n diff(e.storageAfterAccept.cookies, e.storageAfter.cookies, \"Widerruf-Diff Cookies\"),\n diff(e.storageAfterAccept.localStorageKeys, e.storageAfter.localStorageKeys, \"Widerruf-Diff localStorage\"),\n entriesDiff(e.storageAfterAccept.localStorageEntries, e.storageAfter.localStorageEntries, \"Widerruf-Diff Consent-Werte\"),\n ].join(\"\")\n : \"\";\n\n const residual = e.residualAfterRevoke?.length\n ? `<p class=\"residual\"><strong>Residual nach Widerruf:</strong>\n ${e.residualAfterRevoke.map((r) => `<code>${esc(r)}</code>`).join(\" \")}\n <span class=\"warn-text\">— diese IDs bleiben zurück</span></p>`\n : e.residualAfterRevoke\n ? `<p class=\"muted-line\">Keine Residual-IDs nach Widerruf.</p>`\n : \"\";\n\n const shots =\n e.screenshots ??\n (e.screenshotPath ? [{ label: \"Screenshot\", path: e.screenshotPath, at: e.checkedAt }] : []);\n const gallery = shots.length\n ? `<div class=\"shots\">${shots\n .map((s) => {\n const src = shotSrc(s.path);\n const media = src\n ? `<img class=\"shot\" src=\"${src}\" alt=\"${esc(s.label)}\" loading=\"lazy\">`\n : `<code class=\"shot-path\">evidence/${esc(path.basename(s.path))}</code>`;\n return `<figure>\n <figcaption><span class=\"shot-label\">${esc(s.label)}</span>\n <span class=\"ts\">${esc(fmtTime(s.at))}</span></figcaption>\n ${media}\n </figure>`;\n })\n .join(\"\")}</div>`\n : \"\";\n\n return `<article class=\"scard s-${statusClass(e.status)}\">\n <header class=\"shead\">\n <div class=\"stitle\"><code class=\"sname\">${esc(e.scenario)}</code>\n <span class=\"badge ${statusClass(e.status)}\">${statusLabel(e.status)}</span>\n </div>\n <p class=\"snote\">${esc(e.note)}</p>\n </header>\n\n <div class=\"sbody\">\n <h4>Ablauf</h4>\n <div class=\"chips\">${chips || '<span class=\"chip muted\">keine Aktionen protokolliert</span>'}</div>\n ${actionRows ? `<details open><summary>Aktions-Zeitlinie (${(e.actionTimeline ?? []).length})</summary>\n <table class=\"mini\"><tbody>${actionRows}</tbody></table></details>` : \"\"}\n\n ${reqRows ? `<h4>Tracker-Requests</h4>\n <table class=\"mini\">\n <thead><tr><th>Zeit</th><th>Tracker</th><th>Phase</th><th>Request</th></tr></thead>\n <tbody>${reqRows}</tbody>\n </table>` : `<p class=\"muted-line\">Keine Tracker-Requests in diesem Szenario erfasst.</p>`}\n\n ${peakDiff ? `<h4>Storage-Diff Widerruf (Peak nach Accept → Endzustand)</h4>${peakDiff}` : \"\"}\n ${storageDiff ? `<h4>Storage-Diff</h4>${storageDiff}` : \"\"}\n ${residual}\n ${gallery}\n </div>\n <footer class=\"sfoot\">geprüft ${esc(fmtTime(e.checkedAt))} · <code>${esc(e.targetUrl)}</code></footer>\n </article>`;\n })\n .join(\"\\n\");\n\n // --- Empfehlungen: ausschliesslich aus belegten Befunden ---\n const recs: string[] = [];\n const ruleSet = new Set(report.violations.map((v) => v.ruleId ?? \"pre-consent-tracking\"));\n if (ruleSet.has(\"pre-consent-tracking\") || ruleSet.has(\"pre-consent-embed\") || ruleSet.has(\"tracking-without-consent\")) {\n recs.push(\n \"Alle Pre-Consent-Tracker und -Embeds bis zur Einwilligung abschalten (Defer-Muster) oder in die CMP-Steuerung hängen — belegt durch die Befunde im Register.\"\n );\n }\n if (ruleSet.has(\"tracking-after-revoke\") || ruleSet.has(\"tracking-after-deny\")) {\n recs.push(\n \"Tracking nach Widerruf/Ablehnung stoppen: Consent-Status server- und clientseitig respektieren — belegt durch die Befunde im Register.\"\n );\n }\n if (ruleSet.has(\"tracking-declined-category\")) {\n recs.push(\n \"Kategorie-Selektivität der CMP umsetzen: abgelehnte Kategorien (Marketing) dürfen keine Tracker starten — belegt durch die Befunde im Register.\"\n );\n }\n if (ruleSet.has(\"duplicate-events\")) {\n recs.push(\n \"Doppelte Analytics-Einträge vermeiden: genau eine Tracking-Quelle betreiben (z. B. nur gtag oder nur Tag-Manager) — belegt durch die Befunde im Register.\"\n );\n }\n if (ruleSet.has(\"consent-mode-mismatch\")) {\n recs.push(\n \"Consent Mode v2 konsistent implementieren: Zustände und tatsächliche Google-Requests/Cookies müssen zusammenpassen — belegt durch die Befunde im Register.\"\n );\n }\n const residualEvidence = evidence.some((e) => (e.residualAfterRevoke?.length ?? 0) > 0);\n if (residualEvidence) {\n recs.push(\n \"Widerruf muss die gefundenen Tracker-Cookies und -IDs bereinigen — im Bericht sind Residual-IDs nach Widerruf dokumentiert. CMP-Entscheidungsspeicher (z. B. OptanonConsent) davon unterscheiden und nicht löschen.\"\n );\n }\n const darkPattern = evidence.some(\n (e) => e.scenario === \"mobile-usability\" && e.status === \"suspicious\"\n );\n if (darkPattern) {\n recs.push(\n \"Mobile Banner-Bedienung anpassen: «Ablehnen» ist im Test nicht gleichwertig bedienbar wie «Akzeptieren» (Dark-Pattern-Verdacht, siehe Szenario mobile-usability).\"\n );\n }\n if (flagged > 0 && recs.length === 0) {\n recs.push(\n \"Auffällige Szenarien prüfen und die genannten Beobachtungen im Detail bewerten (siehe Szenario-Karten).\"\n );\n }\n if (uncheckable > 0 || notApplicable > 0) {\n recs.push(\n \"Nicht abschliessend bewertete Szenarien manuell prüfen, bevor das Ergebnis gewertet wird — ein fehlendes Prüfmerkmal ist kein grünes Häkchen.\"\n );\n }\n if (recs.length === 0) {\n recs.push(\n \"Keine offenen technischen Befunde. Empfehlung: Scan als Gate in die CI aufnehmen, um Regressionen zu verhindern.\"\n );\n }\n const recItems = recs.map((r) => `<li>${esc(r)}</li>`).join(\"\");\n const solutions = codeSolutionsFor(report);\n const problemGroups = groupFindings(report.violations ?? []);\n const problemRows = problemGroups\n .map(\n (g, i) => `<tr>\n <td class=\"nr\">${i + 1}</td>\n <td><strong>${esc(g.trackerName)}</strong></td>\n <td><code>${esc(g.ruleId)}</code></td>\n <td>${esc(reproductionText(g.count))}</td>\n </tr>`\n )\n .join(\"\");\n const solutionCards = solutions\n .map(\n (s) => `<article class=\"solution\">\n <h3>${esc(s.title)}</h3>\n <span class=\"rule\">${esc(s.ruleId)}</span>\n <pre><code>${esc(s.code)}</code></pre>\n </article>`\n )\n .join(\"\\n\");\n\n // --- Befunde-Register ---\n const leakRows = report.violations\n .map(\n (v) => `<tr>\n <td><code>${esc(v.scenario)}</code></td>\n <td><strong>${esc(v.trackerName)}</strong><div class=\"muted-line\">${esc(v.trackerCategory)}</div></td>\n <td><code title=\"${esc(v.requestUrl)}\">${esc(v.requestUrl.slice(0, 120))}${v.requestUrl.length > 120 ? \"…\" : \"\"}</code><div class=\"muted-line full-url\">${esc(v.requestUrl)}</div></td>\n <td class=\"ts\">${esc(fmtTime(v.timestamp))}</td>\n </tr>`\n )\n .join(\"\\n\");\n\n // --- Beobachtete Requests (inkl. Timelines ohne Violation-Row) ---\n const observedRows = observed\n .map(\n (o) => `<tr>\n <td><code>${esc(o.scenario)}</code></td>\n <td class=\"ts\">${esc(fmtTime(o.at))}</td>\n <td>${esc(o.trackerName)}</td>\n <td><span class=\"phase phase-${o.phase.replace(/[^a-z]/g, \"\")}\">${esc(o.phase)}</span></td>\n <td><code>${esc(o.url.slice(0, 100))}</code></td>\n </tr>`\n )\n .join(\"\\n\");\n\n const demoBanner = options.demo\n ? `<div class=\"demo-banner\"><strong>Demo-Report</strong> · synthetische Testdaten — keine realen Kundendaten.</div>`\n : \"\";\n\n return `<!DOCTYPE html>\n<html lang=\"de-CH\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>CuonzTech · ${esc(title)}</title>\n<style>\n :root {\n --bg: #05070D; --bg2: #070B13; --panel: #0C111D;\n --gold: #D6B56D; --gold-hell: #F4DDA0; --bronze: #A8966A;\n --text: #F5F2EA; --soft: #D9D2BF; --muted: #9A9384;\n --ok: #7EE7B6; --warn: #FF7777; --skip: #9A9384;\n --cyan: #67E8F9; --violet: #8B5CF6;\n --serif: \"Cormorant Garamond\", Georgia, serif;\n --sans: Inter, \"Segoe UI\", system-ui, sans-serif;\n --mono: ui-monospace, \"Cascadia Code\", Consolas, monospace;\n }\n * { box-sizing: border-box; -webkit-print-color-adjust: exact; print-color-adjust: exact; }\n html { background: var(--bg); }\n body {\n margin: 0; background: var(--bg); color: var(--text); font: 16px/1.65 var(--sans);\n background-image: radial-gradient(ellipse 90% 42% at 50% -12%, rgba(214,181,109,0.16), transparent);\n }\n code { font: 13px/1.5 var(--mono); color: var(--gold-hell); background: rgba(214,181,109,0.09); padding: 2px 6px; border-radius: 4px; word-break: break-all; }\n\n .demo-banner {\n background: #2A2416; border-bottom: 1px solid var(--gold);\n color: var(--gold-hell); text-align: center; padding: 10px 16px;\n font: 600 12px/1.5 var(--sans); letter-spacing: 0.12em; text-transform: uppercase;\n }\n\n .hero {\n padding: 64px 24px 40px; text-align: center;\n border-bottom: 1px solid rgba(214,181,109,0.28);\n background-color: var(--bg);\n background-image: linear-gradient(180deg, rgba(12,17,29,0.95), transparent);\n }\n .marke { font: 600 12px/1 var(--sans); letter-spacing: 0.34em; color: var(--gold); text-transform: uppercase; }\n .hero h1 {\n font: 500 clamp(32px, 6vw, 52px)/1.1 var(--serif); color: var(--gold-hell);\n margin: 18px auto 10px; max-width: 20ch;\n }\n .hero .lede { max-width: 62ch; margin: 0 auto; color: var(--soft); font-size: 17px; }\n .hero-meta { display: flex; flex-wrap: wrap; gap: 10px 22px; justify-content: center; margin: 22px 0 6px; color: var(--muted); font-size: 13px; }\n .hero-meta code { font-size: 12px; }\n .gate {\n display: inline-block; margin-top: 18px; padding: 14px 22px; border-radius: 12px;\n border: 1px solid var(--gold); color: var(--gold); max-width: 62ch; text-align: left;\n background: rgba(214,181,109,0.06);\n }\n .gate.blocked { border-color: var(--warn); color: var(--warn); box-shadow: 0 0 24px rgba(255,119,119,0.18); }\n .gate .gtitle { font: 600 13px/1.4 var(--sans); letter-spacing: 0.14em; text-transform: uppercase; }\n .gate .gdetail { display: block; margin-top: 8px; font-size: 13px; color: var(--soft); letter-spacing: 0; text-transform: none; }\n\n main { max-width: 1080px; margin: 0 auto; padding: 36px 22px 80px; background: var(--bg); }\n h2 {\n font: 500 30px/1.2 var(--serif); color: var(--gold); margin: 52px 0 8px;\n padding-bottom: 10px; border-bottom: 1px solid rgba(214,181,109,0.22);\n }\n h2 .num { color: var(--bronze); font-size: 0.7em; letter-spacing: 0.12em; margin-right: 12px; vertical-align: middle; }\n .sub { color: var(--muted); font-size: 14px; margin: 0 0 22px; max-width: 70ch; }\n\n .kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(148px, 1fr)); gap: 12px; margin: 26px 0 8px; }\n .kpi {\n background: var(--panel); border: 1px solid rgba(214,181,109,0.18); border-radius: 12px;\n padding: 18px 16px; text-align: center;\n }\n .kpi .val { font: 600 34px/1.1 var(--serif); display: block; }\n .kpi .lab { font: 600 10px/1.4 var(--sans); letter-spacing: 0.16em; text-transform: uppercase; color: var(--muted); margin-top: 6px; }\n .kpi.gold .val { color: var(--gold-hell); }\n .kpi.ok .val { color: var(--ok); }\n .kpi.warn .val { color: var(--warn); }\n .kpi.skip .val { color: var(--skip); }\n\n .note {\n margin: 26px 0; padding: 16px 20px; border-left: 3px solid var(--gold);\n background: rgba(214,181,109,0.09); color: var(--soft); font-size: 14px; border-radius: 0 10px 10px 0;\n }\n .jgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 14px; }\n .jcard {\n background: var(--panel); border: 1px solid rgba(214,181,109,0.16); border-radius: 12px; padding: 18px;\n }\n .jcard h3 { margin: 0; font: 600 18px/1.3 var(--serif); color: var(--text); display: inline; margin-left: 8px; }\n .jcard header { display: flex; align-items: center; margin-bottom: 10px; }\n .jframe { color: var(--soft); font-size: 13px; margin: 0 0 10px; }\n .jfw { color: var(--muted); font-size: 11px; margin: 0; letter-spacing: 0.04em; }\n .sev {\n font: 700 11px/1 var(--sans); letter-spacing: 0.1em; padding: 5px 9px; border-radius: 6px;\n }\n .sev-gold { background: rgba(214,181,109,0.16); color: var(--gold); border: 1px solid rgba(214,181,109,0.45); }\n .sev-warn { background: rgba(255,119,119,0.16); color: var(--warn); border: 1px solid rgba(255,119,119,0.45); }\n .sev-skip { background: rgba(154,147,132,0.16); color: var(--skip); border: 1px solid rgba(154,147,132,0.45); }\n\n .scard {\n background: var(--panel); border: 1px solid rgba(214,181,109,0.16); border-radius: 14px;\n margin: 18px 0; overflow: hidden;\n }\n .scard.s-ok { border-left: 4px solid var(--ok); }\n .scard.s-warn { border-left: 4px solid var(--warn); }\n .scard.s-skip { border-left: 4px solid var(--skip); }\n .shead { padding: 20px 22px 14px; border-bottom: 1px solid rgba(214,181,109,0.12); background: rgba(214,181,109,0.04); }\n .stitle { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }\n .sname { font-size: 15px; padding: 5px 10px; }\n .snote { margin: 10px 0 0; color: var(--soft); font-size: 15px; }\n .sbody { padding: 18px 22px; }\n .sbody h4 {\n font: 600 11px/1 var(--sans); letter-spacing: 0.18em; text-transform: uppercase;\n color: var(--muted); margin: 20px 0 10px;\n }\n .sbody h4:first-child { margin-top: 0; }\n .sfoot { padding: 12px 22px; border-top: 1px solid rgba(214,181,109,0.12); color: var(--muted); font-size: 11px; }\n .sfoot code { font-size: 11px; }\n\n .badge {\n display: inline-block; padding: 5px 14px; border-radius: 999px;\n font: 600 11px/1.3 var(--sans); letter-spacing: 0.1em; text-transform: uppercase;\n }\n .badge.ok { background: rgba(126,231,182,0.15); color: var(--ok); border: 1px solid rgba(126,231,182,0.42); }\n .badge.warn { background: rgba(255,119,119,0.15); color: var(--warn); border: 1px solid rgba(255,119,119,0.42); }\n .badge.skip { background: rgba(154,147,132,0.15); color: var(--skip); border: 1px solid rgba(154,147,132,0.42); }\n\n .chips { display: flex; flex-wrap: wrap; gap: 8px; }\n .chip {\n font: 500 12px/1 var(--mono); color: var(--cyan); background: rgba(103,232,249,0.1);\n border: 1px solid rgba(103,232,249,0.28); padding: 6px 10px; border-radius: 999px;\n }\n .chip.muted { color: var(--muted); background: rgba(154,147,132,0.1); border-color: rgba(154,147,132,0.28); }\n\n table.mini { width: 100%; border-collapse: collapse; font-size: 13px; margin: 4px 0 8px; }\n table.mini th {\n text-align: left; font: 600 10px/1 var(--sans); letter-spacing: 0.14em; text-transform: uppercase;\n color: var(--muted); padding: 8px 10px; border-bottom: 1px solid rgba(214,181,109,0.28);\n }\n table.mini td { padding: 8px 10px; border-bottom: 1px solid rgba(214,181,109,0.1); color: var(--soft); vertical-align: top; }\n .ts { white-space: nowrap; color: var(--muted); font-size: 11px; }\n .phase { font: 600 10px/1 var(--sans); letter-spacing: 0.08em; text-transform: uppercase; padding: 4px 8px; border-radius: 5px; }\n .phase-preconsent { background: rgba(255,119,119,0.14); color: var(--warn); }\n .phase-postaccept { background: rgba(126,231,182,0.14); color: var(--ok); }\n .phase-postreject, .phase-postrejectrestart { background: rgba(255,119,119,0.14); color: var(--warn); }\n .phase-postselection { background: rgba(126,231,182,0.14); color: var(--ok); }\n .phase-postrevoke { background: rgba(255,119,119,0.14); color: var(--warn); }\n .phase-postwipe { background: rgba(255,119,119,0.14); color: var(--warn); }\n .phase-other { background: rgba(154,147,132,0.14); color: var(--skip); }\n\n .diff { font-size: 13px; color: var(--soft); }\n .add { color: var(--ok); font-family: var(--mono); margin-right: 8px; }\n .del { color: var(--warn); font-family: var(--mono); margin-right: 8px; }\n .residual { font-size: 13px; color: var(--soft); }\n .warn-text { color: var(--warn); }\n .muted-line { color: var(--muted); font-size: 12px; margin-top: 2px; }\n .full-url { display: none; font-family: var(--mono); font-size: 10px; word-break: break-all; }\n @media print {\n .full-url { display: block; }\n }\n\n .sname {\n overflow-wrap: normal;\n word-break: keep-all;\n }\n\n .shots { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 12px; margin-top: 8px; }\n .shots figure {\n margin: 0; background: var(--bg2); border: 1px solid rgba(214,181,109,0.18); border-radius: 10px; padding: 12px;\n break-inside: avoid; page-break-inside: avoid;\n }\n .shots figcaption { display: flex; justify-content: space-between; gap: 8px; margin-bottom: 8px; }\n .shot-label { font: 600 11px/1.3 var(--sans); letter-spacing: 0.08em; text-transform: uppercase; color: var(--gold); }\n .shot-path { display: block; font-size: 11px; color: var(--muted); background: none; padding: 0; }\n .shot { width: 100%; border-radius: 6px; border: 1px solid rgba(214,181,109,0.2); }\n\n details { margin: 8px 0; }\n summary { cursor: pointer; color: var(--gold); font-size: 12px; letter-spacing: 0.06em; }\n\n .recs { counter-reset: rec; list-style: none; padding: 0; margin: 18px 0; }\n .recs li {\n counter-increment: rec; position: relative; padding: 16px 18px 16px 62px;\n background: var(--panel); border: 1px solid rgba(214,181,109,0.16); border-radius: 12px;\n margin: 10px 0; color: var(--soft); font-size: 15px;\n }\n .recs li::before {\n content: counter(rec, decimal-leading-zero); position: absolute; left: 18px; top: 16px;\n font: 600 18px/1 var(--serif); color: var(--gold);\n }\n\n .solutions { display: grid; gap: 14px; margin: 18px 0; }\n .solution {\n background: var(--panel); border: 1px solid rgba(214,181,109,0.18); border-radius: 12px; padding: 16px 18px;\n }\n .solution h3 { margin: 0 0 4px; font: 600 17px/1.3 var(--serif); color: var(--gold-hell); }\n .solution .rule { font: 11px/1 var(--mono); color: var(--gold); letter-spacing: 0.04em; margin-bottom: 10px; display: block; }\n .solution pre {\n margin: 10px 0 0; padding: 14px 16px; overflow-x: auto;\n background: var(--bg2); border: 1px solid rgba(214,181,109,0.12); border-radius: 8px;\n font: 12px/1.55 var(--mono); color: var(--soft); white-space: pre;\n }\n\n .fuss {\n text-align: center; color: var(--muted); font-size: 12px; padding: 28px;\n border-top: 1px solid rgba(214,181,109,0.2); margin-top: 40px;\n }\n .fuss .claim { font: 500 16px/1.4 var(--serif); color: var(--gold); display: block; margin-bottom: 6px; }\n\n @media print {\n html, body { background: var(--bg); color: var(--text); }\n .scard, .kpi, .jcard, .recs li, .solution, .shots figure { break-inside: avoid; page-break-inside: avoid; }\n .hero, main, .fuss, .demo-banner { break-inside: avoid; }\n /* Überschrift mit Folgeinhalt halten (Jurisdictions → Karten) */\n h2, h3, h4, .stitle { break-after: avoid; page-break-after: avoid; }\n .shead { break-inside: avoid; }\n .jgrid { break-inside: avoid; }\n /* Fusszeile (geprüft · URL) beim Szenario halten */\n .sfoot { break-before: avoid; page-break-before: avoid; break-inside: avoid; }\n .sbody { break-inside: auto; }\n /* Technische Szenarionamen nicht mitten im Wort trennen */\n .sname, code { overflow-wrap: normal; word-break: keep-all; }\n details[open] > summary, details:not([open]) > summary { list-style: none; display: none; }\n details { display: block; }\n details > *:not(summary) { display: block !important; }\n }\n</style>\n</head>\n<body>\n${demoBanner}\n<header class=\"hero\">\n <div class=\"marke\">CuonzTech · Privacy Chaos Gate</div>\n <h1>${esc(title)}</h1>\n <p class=\"lede\">Aggressiver Consent-Stresstest: ${evidence.length} ausgeführte Chaos-Szenarien, ${findingsCountText(report.totalViolations)}, ${observed.length} beobachtete Tracker-Requests. Beweise mit Zeitlinie und Storage-Vergleich.</p>\n <p class=\"lede problems\" id=\"problem-summary\"><strong>${facts.problemsText}</strong> — aus ${findingsCountText(report.totalViolations)} destilliert.${solutions.length > 0 ? \" Was zuerst zu beheben ist, steht unter Code-Lösungen.\" : \"\"}</p>\n <div class=\"hero-meta\">\n <span>Ziel: <code>${esc(report.targetUrl)}</code></span>\n <span>Scan: ${esc(fmtTime(report.scannedAt))}</span>\n <span>Dauer: ${esc(fmtDuration(report.durationMs))}</span>\n </div>\n <div class=\"gate ${gateClass}\">\n <span class=\"gtitle\">${esc(gateTitle)}</span>\n <span class=\"gdetail\">${esc(gateDetail)}</span>\n </div>\n</header>\n<main>\n <h2><span class=\"num\">01</span>Executive Summary</h2>\n <p class=\"sub\">Ausschliesslich abgeleitet aus den tatsächlich ausgeführten Szenarien dieses Scans.</p>\n <div id=\"summary\">${summaryHtml}</div>\n <div class=\"kpis\">\n ${kpis\n .map((k) => `<div class=\"kpi ${k.tone}\"><span class=\"val\">${esc(k.value)}</span><span class=\"lab\">${esc(k.label)}</span></div>`)\n .join(\"\\n \")}\n </div>\n\n <div class=\"note\"><strong>Hinweis:</strong> Technisches Hilfsmittel, keine Rechtsberatung. / Technical aid, not legal advice. Die Schweregrad-Einstufung je Rechtsraum ist eine technisch-juristische Einordnungshilfe und ersetzt keine Beratung.</div>\n\n <h2><span class=\"num\">02</span>Jurisdictions</h2>\n <p class=\"sub\">Dieselben technischen Fakten, unterschiedliche Konsequenz. Die Einstufung erfolgt je Rechtsraum — eine globale Compliance-Aussage wäre unseriös.</p>\n <div class=\"jgrid\">\n ${jCards}\n </div>\n\n <h2><span class=\"num\">03</span>Szenarien &amp; Beweise</h2>\n <p class=\"sub\">Jedes ausgeführte Szenario mit Status, Ablauf, Tracker-Requests, Storage-Diff und Screenshots. Ein nicht gefundenes Merkmal ergibt kein grünes Häkchen — sondern «nicht prüfbar».</p>\n ${cards}\n\n ${\n report.violations.length > 0\n ? `<h2><span class=\"num\">04</span>Befunde (Regelverstösse)</h2>\n <p class=\"sub\">Vollständige Liste der dokumentierten Tracker-Requests ohne gültige Einwilligung — verletzt die konfigurierte Regel «Keine Analytics-Requests vor Zustimmung».</p>\n <table class=\"mini\">\n <thead><tr><th>Szenario</th><th>Tracker</th><th>Request</th><th>Zeit</th></tr></thead>\n <tbody>${leakRows}</tbody>\n </table>`\n : \"\"\n }\n\n ${\n problemGroups.length > 0\n ? `<h2><span class=\"num\">05</span>Was zuerst beheben</h2>\n <p class=\"sub\">${esc(facts.problemsText)} — gruppiert aus ${esc(findingsCountText(report.totalViolations))}. «N Requests» zählt die dokumentierten Zeilen derselben Ursache, nicht unabhängige Testläufe.</p>\n <table class=\"mini\">\n <thead><tr><th>#</th><th>Tracker</th><th>Regel</th><th>Reproduktion</th></tr></thead>\n <tbody>${problemRows}</tbody>\n </table>`\n : \"\"\n }\n\n ${\n observed.length > 0\n ? `<h2><span class=\"num\">06</span>Beobachtete Tracker-Requests</h2>\n <p class=\"sub\">Alle erfassten Tracker-Requests aus den Szenario-Timelines — auch solche, die keine eigene Violation-Row erzeugt haben. ${esc(findingsCountText(report.totalViolations))} gegenüber ${observed.length === 1 ? \"1 Beobachtung\" : `${observed.length} Beobachtungen`}.</p>\n <table class=\"mini\">\n <thead><tr><th>Szenario</th><th>Zeit</th><th>Tracker</th><th>Phase</th><th>Request</th></tr></thead>\n <tbody>${observedRows}</tbody>\n </table>`\n : \"\"\n }\n\n <h2><span class=\"num\">07</span>Empfehlungen</h2>\n <p class=\"sub\">Ausschliesslich aus belegten Befunden dieses Scans abgeleitet — Beobachtung und Massnahme getrennt.</p>\n <ol class=\"recs\" id=\"recommendations\">\n ${recItems}\n </ol>\n ${\n solutions.length > 0\n ? `<h2><span class=\"num\">08</span>Code-Lösungen</h2>\n <p class=\"sub\">Schematische Umsetzungsmuster zu den verletzten Regeln dieses Scans — an die eigene CMP/Tracker-Stack anpassen, kein Copy-Paste-Fix.</p>\n <div class=\"solutions\" id=\"code-solutions\">\n ${solutionCards}\n </div>`\n : \"\"\n }\n</main>\n<footer class=\"fuss\">\n <span class=\"claim\">KI-Systeme, die bleiben.</span>\n © CuonzTech · Privacy Chaos Gate · Technisches Hilfsmittel, keine Rechtsberatung.\n</footer>\n</body>\n</html>`;\n}\n","import path from \"node:path\";\nimport fs from \"node:fs/promises\";\nimport type { LeakReport } from \"../../types/index.js\";\n\n/**\n * Kunden-Delivery für den CHF-890-Pilot: Deckblatt im CuonzTech-Brand\n * vor dem Evidence-Report, gerendert als ein PDF.\n * Versand per Mail — der Kunde erhält eine Datei, die teuer aussieht.\n */\n\nexport interface CoverOptions {\n /** Empfängername für das Deckblatt (optional, Demo = anonymisiert) */\n clientName?: string;\n /** Ausstellungsdatum, Default: Scan-Datum */\n issuedAt?: string;\n /** Demo-Lauf mit synthetischen Testdaten — muss aufs Deckblatt */\n demo?: boolean;\n}\n\nconst esc = (s: string): string =>\n s\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n\nconst FONT_LINKS = `<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n<link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n<link href=\"https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@500;600;700&family=Inter:wght@400;500;600;700&display=swap\" rel=\"stylesheet\">`;\n\nexport function buildCoverHtml(report: LeakReport, options: CoverOptions = {}): string {\n const client = options.clientName ?? \"pilot-kunde.ch\";\n const issued = options.issuedAt ?? report.scannedAt;\n const gate = report.totalViolations === 0 ? \"PASS\" : \"BLOCKED\";\n const gateTone = report.totalViolations === 0 ? \"ok\" : \"blocked\";\n const scenarios = report.evidence?.length ?? 0;\n const demoBadge = options.demo\n ? `<div class=\"demo-badge\">Demo-Report · synthetische Testdaten — keine realen Kundendaten</div>`\n : \"\";\n\n return `<!DOCTYPE html>\n<html lang=\"de-CH\">\n<head>\n<meta charset=\"utf-8\">\n<title>CuonzTech · Prüfbericht</title>\n${FONT_LINKS}\n<style>\n :root {\n --bg: #05070D; --panel: #0C111D; --gold: #D6B56D; --gold-hell: #F4DDA0;\n --text: #F5F2EA; --soft: #D9D2BF; --muted: #9A9384;\n --ok: #7EE7B6; --warn: #FF7777;\n --serif: \"Cormorant Garamond\", \"Times New Roman\", Georgia, serif;\n --sans: Inter, \"Segoe UI\", system-ui, sans-serif;\n --mono: ui-monospace, Consolas, monospace;\n }\n * { box-sizing: border-box; }\n html, body { margin: 0; padding: 0; background: var(--bg); }\n .cover {\n width: 100%; min-height: 297mm; padding: 26mm 24mm 22mm;\n background: var(--bg); color: var(--text);\n background-image:\n radial-gradient(ellipse 90% 45% at 50% -12%, rgba(214,181,109,0.18), transparent),\n linear-gradient(180deg, rgba(214,181,109,0.06) 0, transparent 28%);\n font-family: var(--sans);\n page-break-after: always;\n display: flex; flex-direction: column;\n }\n .cover::before {\n content: \"\"; display: block; height: 3px; margin: -26mm -24mm 18mm;\n background: linear-gradient(90deg, var(--gold) 0%, rgba(214,181,109,0.15) 70%, transparent);\n }\n .marke {\n font: 600 11px/1 var(--sans); letter-spacing: 0.34em;\n color: var(--gold); text-transform: uppercase;\n display: flex; align-items: center; gap: 12px;\n }\n .marke .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--gold); flex: 0 0 auto; }\n h1 {\n font: 600 54px/1.05 var(--serif); color: var(--gold-hell);\n margin: 14mm 0 6mm; max-width: 14ch;\n }\n .lede { color: var(--soft); font-size: 15px; max-width: 54ch; line-height: 1.75; margin: 0; }\n .rule {\n height: 1px; margin: 12mm 0 10mm; border: 0;\n background: linear-gradient(90deg, rgba(214,181,109,0.55), rgba(214,181,109,0.08));\n }\n .fakten { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }\n .fakt {\n background: var(--panel); border: 1px solid rgba(214,181,109,0.22);\n border-radius: 10px; padding: 16px 18px;\n }\n .fakt .lab {\n font: 600 9px/1.4 var(--sans); letter-spacing: 0.16em;\n text-transform: uppercase; color: var(--muted);\n }\n .fakt .val { font: 600 22px/1.25 var(--serif); color: var(--gold-hell); margin-top: 6px; word-break: break-word; }\n .fakt .val.sm { font-size: 15px; font-family: var(--sans); font-weight: 500; color: var(--text); }\n .fakt.wide { grid-column: 1 / -1; }\n .gate {\n margin-top: 12mm; padding: 18px 22px; border-radius: 12px;\n border: 1px solid var(--gold); background: rgba(214,181,109,0.07);\n }\n .gate .gtitle {\n font: 600 13px/1 var(--sans); letter-spacing: 0.16em; text-transform: uppercase;\n color: var(--gold);\n }\n .gate.blocked { border-color: var(--warn); background: rgba(255,119,119,0.08); }\n .gate.blocked .gtitle { color: var(--warn); }\n .gate .gdetail { margin: 10px 0 0; font-size: 13px; line-height: 1.65; color: var(--soft); }\n .stats {\n display: flex; gap: 28px; margin-top: 10mm; color: var(--muted);\n font: 500 12px/1.4 var(--sans); letter-spacing: 0.06em;\n }\n .stats b { display: block; font: 600 28px/1.1 var(--serif); color: var(--gold-hell); letter-spacing: 0; }\n .sign {\n margin-top: auto; padding-top: 8mm;\n display: flex; justify-content: space-between; align-items: flex-end; gap: 24px;\n }\n .sign .line {\n width: 62mm; border-top: 1px solid rgba(214,181,109,0.45); padding-top: 8px;\n color: var(--muted); font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase;\n }\n .legal {\n margin-top: 8mm; padding-top: 10px;\n color: var(--muted); font-size: 10px; line-height: 1.65;\n border-top: 1px solid rgba(214,181,109,0.25);\n max-width: 100%;\n }\n .demo-badge {\n display: inline-block; margin: 0 0 8mm; padding: 10px 14px;\n border: 1px solid var(--gold); border-radius: 4px;\n color: var(--gold-hell); background: rgba(214,181,109,0.12);\n font: 600 12px/1.4 var(--sans); letter-spacing: 0.08em; text-transform: uppercase;\n }\n</style>\n</head>\n<body>\n<div class=\"cover\">\n <div class=\"marke\"><span class=\"dot\"></span>CuonzTech · Privacy Chaos Gate</div>\n ${demoBadge}\n <h1>Consent-Prüfbericht</h1>\n <p class=\"lede\">Dieser Bericht fasst zusammen, ob Tracking vor der Einwilligung ausbleibt,\n ob erlaubtes Tracking danach korrekt startet und ob Widerruf sowie Kategorie-Auswahl\n zuverlässig funktionieren. Grundlage ist ein automatisierter Stresstest mit\n ${scenarios} Chaos-Szenarien.</p>\n\n <hr class=\"rule\">\n\n <div class=\"fakten\">\n <div class=\"fakt\"><div class=\"lab\">Kunde</div><div class=\"val\">${esc(client)}</div></div>\n <div class=\"fakt\"><div class=\"lab\">Scan-Datum</div><div class=\"val sm\">${esc(new Date(issued).toLocaleDateString(\"de-CH\", { dateStyle: \"long\" }))}</div></div>\n <div class=\"fakt wide\"><div class=\"lab\">Geprüftes System</div><div class=\"val sm\">${esc(report.targetUrl)}</div></div>\n </div>\n\n <div class=\"gate ${gateTone}\">\n <div class=\"gtitle\">Technisches Gate: ${gate}</div>\n <p class=\"gdetail\">${report.totalViolations === 0\n ? \"Keine dokumentierten Tracker-Funde in den ausgeführten Szenarien. Eine rechtliche Gesamtbewertung erfolgt nicht.\"\n : `${report.totalViolations === 1 ? \"1 dokumentierte Befund-Zeile\" : `${report.totalViolations} dokumentierte Befund-Zeilen`} in den ausgeführten Szenarien. Eine rechtliche Gesamtbewertung erfolgt nicht.`}</p>\n </div>\n\n <div class=\"stats\">\n <div><b>${scenarios}</b>Szenarien</div>\n <div><b>${report.totalViolations}</b>Befunde</div>\n <div><b>${(report.evidence ?? []).reduce((n, e) => n + e.requestTimeline.filter((r) => r.trackerName).length, 0)}</b>Tracker-Requests</div>\n </div>\n\n <div class=\"sign\">\n <div class=\"line\">Ort, Datum · Empfangsbestätigung Kunde</div>\n <div class=\"line\">Ausgestellt von CuonzTech</div>\n </div>\n\n <div class=\"legal\">\n Technisches Hilfsmittel, keine Rechtsberatung. / Technical aid, not legal advice.\n Die Rechtsraum-Einordnung im Bericht ist eine technisch-juristische Hilfestellung\n und ersetzt keine Beratung durch eine Fachperson. Automatisierte Prüfung —\n ein nicht gefundenes Merkmal ergibt kein grünes Häkchen.\n </div>\n</div>\n</body>\n</html>`;\n}\n\n/** Extrahiert alle <style>-Blöcke eines HTML-Dokuments. */\nfunction extractStyles(html: string): string {\n return [...html.matchAll(/<style>([\\s\\S]*?)<\\/style>/g)]\n .map((m) => m[1])\n .join(\"\\n\");\n}\n\n/** Extrahiert den <body>-Inhalt ohne die Tags. */\nfunction extractBody(html: string): string {\n return html.match(/<body>([\\s\\S]*)<\\/body>/)?.[1] ?? html;\n}\n\n/**\n * Bevorzugter Weg: Deckblatt und Evidence in einem HTML zusammenführen und\n * in einem Rutsch als PDF rendern. Sauberer Seitenfluss, keine PDF-Lib nötig.\n */\nexport async function renderDeluxeCombined(\n coverHtml: string,\n evidenceHtmlPath: string,\n outPath: string,\n previewDir?: string\n): Promise<string> {\n const { chromium } = await import(\"playwright\");\n const evidenceHtml = await fs.readFile(evidenceHtmlPath, \"utf-8\");\n\n // Cover- UND Evidence-Styles ins kombinierte Dokument — früher wurde nur\n // Evidence übernommen, dadurch fiel das Deckblatt auf Browser-Default zurück.\n const styles = [extractStyles(coverHtml), extractStyles(evidenceHtml)].join(\"\\n\");\n // Evidence-Hero UND Demo-Banner unterdrücken: Deckblatt ist bereits Titelseite\n // inkl. Demo-Kennzeichnung — sonst leere Seite 2.\n const evidenceBody = extractBody(evidenceHtml)\n .replace(/<div class=\"demo-banner\">[\\s\\S]*?<\\/div>\\s*/, \"\")\n .replace(\n /<header class=\"hero\">[\\s\\S]*?<\\/header>/,\n \"\"\n );\n const combined = `<!DOCTYPE html>\n<html lang=\"de-CH\">\n<head>\n<meta charset=\"utf-8\">\n<title>CuonzTech · Consent-Prüfbericht</title>\n${FONT_LINKS}\n<style>\nhtml, body { margin: 0; padding: 0; background: #05070D; }\n * { -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; }\n${styles}\n</style>\n</head>\n<body>\n${extractBody(coverHtml)}\n${evidenceBody}\n</body>\n</html>`;\n\n const browser = await chromium.launch({ headless: true });\n try {\n const page = await browser.newPage();\n await page.setContent(combined, { waitUntil: \"networkidle\" });\n // Warten bis Webfonts geladen sind — sonst Serif-Fallback im PDF\n await page.evaluate(() => (document as any).fonts?.ready ?? Promise.resolve());\n await page.emulateMedia({ media: \"print\" });\n await page.waitForTimeout(400);\n\n // Visuelle Vorschau vor PDF: Seitenweise PNGs (A4 in CSS-px ≈ 794×1123)\n if (previewDir) {\n await fs.mkdir(previewDir, { recursive: true });\n const size = { width: 794, height: 1123 };\n await page.setViewportSize(size);\n const pages = await page.evaluate(() => {\n const el = document.querySelector(\".cover\") ?? document.body;\n const h = Math.max(\n document.documentElement.scrollHeight,\n (el as HTMLElement).scrollHeight\n );\n return Math.ceil(h / 1123);\n });\n for (let i = 0; i < Math.min(pages, 4); i++) {\n await page.evaluate((y) => window.scrollTo(0, y), i * 1123);\n await page.waitForTimeout(150);\n await page.screenshot({\n path: path.join(previewDir, `p${String(i + 1).padStart(2, \"0\")}.png`),\n });\n }\n }\n\n const pdf = await page.pdf({ format: \"A4\", printBackground: true });\n await fs.mkdir(path.dirname(outPath), { recursive: true });\n await fs.writeFile(outPath, pdf);\n return outPath;\n } finally {\n await browser.close().catch(() => {});\n }\n}\n\n/**\n * Rendert Deckblatt + Evidence-HTML zu einem einzigen PDF (Chromium via Playwright).\n * Gibt den Pfad der PDF zurück. Bevorzugt renderDeluxeCombined — dieser Pfad\n * rendert in zwei Dokumenten und muss manuell gemergt werden.\n */\nexport async function renderDeluxePdf(\n coverHtml: string,\n evidenceHtmlPath: string,\n outPath: string\n): Promise<string> {\n return renderDeluxeCombined(coverHtml, evidenceHtmlPath, outPath);\n}\n","import fs from \"node:fs/promises\";\r\nimport path from \"node:path\";\r\nimport pc from \"picocolors\";\r\nimport {\r\n GateConfig,\r\n GateExecutionResult,\r\n LeakReport,\r\n RemediationResult,\r\n} from \"../types/index.js\";\r\nimport { ChaosScannerInterface } from \"./scanner/types.js\";\r\nimport { ChaosScanner } from \"./scanner/index.js\";\r\nimport { RemediationEngineInterface } from \"./remediation/types.js\";\r\nimport { RemediationEngine } from \"./remediation/index.js\";\r\nimport { buildEvidenceHtml, buildEvidenceMarkdown } from \"./report/evidenceReport.js\";\nimport { buildCoverHtml, renderDeluxeCombined } from \"./report/deluxePdf.js\";\r\nimport { escapeCell } from \"./remediation/pullRequest.js\";\r\nimport { LEGAL_DISCLAIMER } from \"./legal/disclaimer.js\";\r\n\r\nexport class PrivacyChaosGate {\r\n private scanner: ChaosScannerInterface;\r\n private remediationEngine: RemediationEngineInterface;\r\n\r\n constructor(\r\n scanner?: ChaosScannerInterface,\r\n remediationEngine?: RemediationEngineInterface\r\n ) {\r\n this.scanner = scanner ?? new ChaosScanner();\r\n this.remediationEngine = remediationEngine ?? new RemediationEngine();\r\n }\r\n\r\n async run(config: GateConfig): Promise<GateExecutionResult> {\r\n console.log(pc.bold(pc.cyan(\"\\n=======================================================\")));\r\n console.log(pc.bold(pc.cyan(\" CUONZTECH PRIVACY CHAOS GATE (CPCG) \")));\r\n console.log(pc.bold(pc.cyan(\"=======================================================\\n\")));\r\n\r\n console.log(pc.blue(\"¹ Target URL: \"), pc.white(config.targetUrl));\r\n console.log(pc.blue(\"¹ Auto-Fix Enabled: \"), pc.white(String(config.autoFix)));\r\n console.log(pc.blue(\"¹ Fail on Leak: \"), pc.white(String(config.failOnLeak)));\r\n console.log(pc.blue(\"¹ Report Output: \"), pc.white(config.reportOutput));\r\n console.log(\"\");\r\n\r\n // Phase 1: SCAN\r\n console.log(pc.bold(pc.yellow(\"–¶ Phase 1: Scanning with Privacy Chaos Routines...\")));\r\n const report: LeakReport = await this.scanner.scan(config);\r\n console.log(\r\n pc.green(`œ Scan complete in ${report.durationMs}ms. Found ${report.totalViolations} leak(s).`)\r\n );\r\n\r\n // Phase 2: ANALYZE\r\n console.log(pc.bold(pc.yellow(\"\\n–¶ Phase 2: Analyzing Privacy Chaos Results...\")));\r\n if (report.totalViolations > 0) {\r\n console.log(pc.red(`œ– Detected ${report.totalViolations} unauthorized tracker leak(s)!`));\r\n for (const violation of report.violations) {\r\n console.log(\r\n pc.red(` [${violation.scenario}] ${violation.trackerName} (${violation.trackerCategory}): ${violation.requestUrl}`)\r\n );\r\n }\r\n } else {\r\n console.log(pc.green(\"œ All privacy chaos tests passed! Zero tracker leaks detected.\"));\r\n }\r\n\r\n // Phase 3: FIX / AUTO-REMEDIATION\r\n let remediation: RemediationResult | undefined;\r\n if (report.totalViolations > 0 && config.autoFix) {\r\n console.log(pc.bold(pc.yellow(\"\\n–¶ Phase 3: Triggering Agentic Auto-Remediation & Review Agent...\")));\r\n remediation = await this.remediationEngine.remediate(report, config);\r\n\r\n if (remediation.reviewVerdict) {\r\n console.log(pc.bold(pc.magenta(\"–¶ Review Agent Evaluation:\")));\r\n console.log(pc.cyan(` Score: ${remediation.reviewVerdict.score}/100 | Passed: ${remediation.reviewVerdict.passed}`));\r\n for (const comment of remediation.reviewVerdict.comments) {\r\n console.log(pc.dim(` ${comment}`));\r\n }\r\n }\r\n\r\n if (remediation.success) {\r\n console.log(pc.green(\"œ Auto-remediation approved and applied successfully!\"));\r\n if (remediation.commitHash) {\r\n console.log(pc.green(`œ Git commit created: ${remediation.commitHash}`));\r\n }\r\n if (remediation.pullRequest) {\r\n if (remediation.pullRequest.prUrl) {\r\n console.log(pc.bold(pc.green(`œ GitHub Pull Request: ${remediation.pullRequest.prUrl}`)));\r\n } else {\r\n console.log(pc.bold(pc.cyan(`œ Fix committed locally on branch '${remediation.pullRequest.branchName}' (no remote/token: no PR opened)`)));\r\n }\r\n }\r\n } else {\r\n console.log(pc.red(`œ– Auto-remediation failed: ${remediation.error ?? \"Unknown error\"}`));\r\n }\r\n }\r\n\r\n // Persist Report to Disk\r\n await this.saveReport(report, config.reportOutput, config.demo === true, config.reportPdf === true, config.clientName);\r\n\r\n // Determine Result & Exit Code\r\n let status: GateExecutionResult[\"status\"] = \"clean\";\r\n let exitCode = 0;\r\n\r\n if (report.totalViolations > 0) {\r\n if (remediation?.success) {\r\n status = \"remediated\";\r\n exitCode = 0;\r\n } else {\r\n status = \"blocked\";\r\n exitCode = config.failOnLeak ? 1 : 0;\r\n }\r\n }\r\n\r\n // GitHub Actions step outputs & summary support\r\n await this.writeGitHubOutputs({\r\n leaksFound: report.totalViolations > 0,\r\n leaksCount: report.totalViolations,\r\n patchApplied: remediation?.success ?? false,\r\n reportPath: path.resolve(config.reportOutput),\r\n });\r\n\r\n await this.writeGitHubSummary(config, report, status, remediation);\r\n\r\n console.log(pc.bold(pc.cyan(\"\\n-------------------------------------------------------\")));\r\n if (status === \"clean\") {\r\n console.log(pc.bold(pc.green(\"œ GATE RESULT: PASS (No privacy leaks)\")));\r\n } else if (status === \"remediated\") {\r\n console.log(pc.bold(pc.green(\"œ GATE RESULT: PASS (Leaks automatically remediated)\")));\r\n } else {\r\n console.log(pc.bold(pc.red(`œ– GATE RESULT: BLOCKED (${report.totalViolations} unpatched leaks)`)));\r\n }\r\n console.log(pc.bold(pc.cyan(\"-------------------------------------------------------\\n\")));\r\n console.log(pc.dim(LEGAL_DISCLAIMER));\r\n console.log(\"\");\r\n\r\n return {\r\n report,\r\n remediation,\r\n status,\r\n exitCode,\r\n };\r\n }\r\n\r\n private async saveReport(report: LeakReport, outputPath: string, demo = false, reportPdf = false, clientName?: string): Promise<void> {\n const resolvedPath = path.resolve(outputPath);\n const dir = path.dirname(resolvedPath);\n await fs.mkdir(dir, { recursive: true });\n // Portables Paket: Screenshot-Pfade relativ halten\n const portable: LeakReport = {\n ...report,\n evidence: (report.evidence ?? []).map((e) => ({\n ...e,\n screenshots: e.screenshots?.map((s) => ({ ...s, path: `evidence/${path.basename(s.path)}` })),\n screenshotPath: e.screenshotPath ? `evidence/${path.basename(e.screenshotPath)}` : e.screenshotPath,\n })),\n };\n await fs.writeFile(resolvedPath, JSON.stringify(portable, null, 2), \"utf-8\");\n console.log(pc.dim(\"Leak report saved to: \" + resolvedPath));\n\n // Portable Evidence-Paket: Screenshots mit relativen Links neben den Report\n const evidenceDir = path.join(dir, \"evidence\");\n const shots: { label: string; path: string; at: string }[] = [];\n for (const e of report.evidence ?? []) {\n for (const s of e.screenshots ?? []) shots.push(s);\n if (e.screenshotPath && !(e.screenshots ?? []).length) {\n shots.push({ label: \"screenshot\", path: e.screenshotPath, at: e.checkedAt });\n }\n }\n if (shots.length) {\n await fs.mkdir(evidenceDir, { recursive: true });\n for (const s of shots) {\n try {\n const dest = path.join(evidenceDir, path.basename(s.path));\n await fs.copyFile(s.path, dest).catch(() => {});\n } catch {\n /* Screenshot nicht kopierbar — HTML bettet data-URI ein */\n }\n }\n console.log(pc.dim(\"Evidence screenshots copied to: \" + evidenceDir));\n }\n\n // Kunden-Report: Markdown + HTML (Drei-Zustand: bestanden / auffällig / nicht prüfbar)\n const base = resolvedPath.replace(/\\.json$/i, \"\");\n const mdPath = base + \"-evidence.md\";\n await fs.writeFile(mdPath, buildEvidenceMarkdown(report, \"Evidence Report\", { demo }), \"utf-8\");\n console.log(pc.dim(\"Evidence report saved to: \" + mdPath));\n\n const htmlPath = base + \"-evidence.html\";\n await fs.writeFile(\n htmlPath,\n buildEvidenceHtml(report, \"Evidence Report\", { demo }),\n \"utf-8\"\n );\n console.log(pc.dim(\"Evidence HTML saved to: \" + htmlPath));\n\n // Deluxe-PDF: Deckblatt + Evidence — die Datei, die zum Kunden geht\n if (reportPdf) {\n try {\n const cover = buildCoverHtml(report, {\n clientName: clientName ?? \"pilot-kunde.ch\",\n issuedAt: report.scannedAt,\n demo,\n });\n const pdfPath = base + \"-deluxe.pdf\";\n await renderDeluxeCombined(cover, htmlPath, pdfPath);\n console.log(pc.dim(\"Deluxe PDF saved to: \" + pdfPath));\n } catch (err) {\n console.log(pc.dim(\"PDF generation skipped: \" + String(err).slice(0, 100)));\n }\n }\n }\n\n private async writeGitHubOutputs(outputs: {\r\n leaksFound: boolean;\r\n leaksCount: number;\r\n patchApplied: boolean;\r\n reportPath: string;\r\n }): Promise<void> {\r\n const githubOutputPath = process.env.GITHUB_OUTPUT;\r\n if (!githubOutputPath) return;\r\n\r\n const lines = [\r\n `leaks_found=${outputs.leaksFound}`,\r\n `leaks_count=${outputs.leaksCount}`,\r\n `patch_applied=${outputs.patchApplied}`,\r\n `report_path=${outputs.reportPath}`,\r\n ].join(\"\\n\");\r\n\r\n try {\r\n await fs.appendFile(githubOutputPath, `${lines}\\n`, \"utf-8\");\r\n } catch (err) {\r\n console.warn(pc.yellow(\"š Could not write to GITHUB_OUTPUT: \" + String(err)));\r\n }\r\n }\r\n\r\n private async writeGitHubSummary(\r\n config: GateConfig,\r\n report: LeakReport,\r\n status: GateExecutionResult[\"status\"],\r\n remediation?: RemediationResult\r\n ): Promise<void> {\r\n const summaryPath = process.env.GITHUB_STEP_SUMMARY;\r\n if (!summaryPath) return;\r\n\r\n const statusBadge =\r\n status === \"clean\"\r\n ? \"### ðŸ›¡ï¸ Cuonztech Privacy Chaos Gate: **PASSED (Clean)**\"\r\n : status === \"remediated\"\r\n ? \"### ðŸ›¡ï¸ Cuonztech Privacy Chaos Gate: **PASSED (Auto-Remediated)**\"\r\n : \"### 🛑 Cuonztech Privacy Chaos Gate: **BLOCKED (Privacy Leaks Found)**\";\r\n\r\n const lines: string[] = [\r\n statusBadge,\r\n \"\",\r\n \"| Metric | Value |\",\r\n \"| :--- | :--- |\",\r\n `| **Target URL** | \\`${config.targetUrl}\\` |`,\r\n `| **Duration** | \\`${report.durationMs}ms\\` |`,\r\n `| **Total Violations** | \\`${report.totalViolations}\\` |`,\r\n `| **Passed Scenarios** | ${report.passedScenarios.map((s) => `\\`${s}\\``).join(\", \") || \"None\"} |`,\r\n `| **Failed Scenarios** | ${report.failedScenarios.map((s) => `\\`${s}\\``).join(\", \") || \"None\"} |`,\r\n \"\",\r\n ];\r\n\r\n if (report.violations.length > 0) {\r\n lines.push(\"#### 🚨 Detected Privacy Leaks\");\r\n lines.push(\"| Scenario | Tracker | Category | Intercepted Request |\");\r\n lines.push(\"| :--- | :--- | :--- | :--- |\");\r\n for (const v of report.violations) {\r\n lines.push(\r\n `| \\`${escapeCell(v.scenario)}\\` | **${escapeCell(v.trackerName)}** | \\`${escapeCell(v.trackerCategory)}\\` | \\`${escapeCell(v.requestUrl)}\\` |`\r\n );\r\n }\r\n lines.push(\"\");\r\n }\r\n\r\n if (remediation) {\r\n lines.push(\"#### 🧠Agentic Auto-Remediation\");\r\n if (remediation.success) {\r\n lines.push(`> **Status:** Patches successfully generated and applied.`);\r\n if (remediation.commitHash) {\r\n lines.push(`> **Git Commit:** \\`${remediation.commitHash}\\``);\r\n }\r\n for (const patch of remediation.patches) {\r\n lines.push(`* **Patched:** \\`${patch.filePath}\\` - ${patch.explanation}`);\r\n }\r\n if (remediation.pullRequest) {\r\n lines.push(\r\n remediation.pullRequest.prUrl\r\n ? `> **Pull Request:** ${remediation.pullRequest.prUrl}`\r\n : `> **Fix committed locally on branch (no remote/token, no PR opened):** \\`${remediation.pullRequest.branchName}\\``\r\n );\r\n }\r\n } else {\r\n lines.push(`> šï¸ **Status:** Auto-remediation failed: ${remediation.error}`);\r\n }\r\n if (remediation.reviewVerdict) {\r\n lines.push(\"\", \"#### 🎠Review Agent Verdict\");\r\n lines.push(`> **Score:** \\`${remediation.reviewVerdict.score}/100\\` | **Passed:** \\`${remediation.reviewVerdict.passed}\\``);\r\n for (const c of remediation.reviewVerdict.comments) {\r\n lines.push(`* ${c.replace(/\\n/g, \" \")}`);\r\n }\r\n }\r\n lines.push(\"\");\r\n }\r\n\r\n try {\r\n await fs.appendFile(summaryPath, lines.join(\"\\n\") + \"\\n\", \"utf-8\");\r\n } catch (err) {\r\n console.warn(pc.yellow(\"š Could not write to GITHUB_STEP_SUMMARY: \" + String(err)));\r\n }\r\n }\r\n}\r\n"],"mappings":"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","names":["storageAfter","status","fs","path","execFile","promisify","execFileAsync","promisify","execFile","fs","path","fs","path","path","fs","e","path","fs","esc","chromium","fs","path","path","fs"]}