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.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { z } from 'zod';
2
- import * as playwright from 'playwright';
3
2
 
4
3
  /**
5
4
  * Chaos test scenarios as defined in PRD Section 2B
@@ -207,17 +206,19 @@ declare const EvidenceRecordSchema: z.ZodObject<{
207
206
  path: z.ZodString;
208
207
  at: z.ZodString;
209
208
  }, "strip", z.ZodTypeAny, {
210
- at: string;
211
209
  path: string;
210
+ at: string;
212
211
  label: string;
213
212
  }, {
214
- at: string;
215
213
  path: string;
214
+ at: string;
216
215
  label: string;
217
216
  }>, "many">>;
218
217
  screenshotPath: z.ZodOptional<z.ZodString>;
219
218
  targetUrl: z.ZodString;
220
219
  checkedAt: z.ZodString;
220
+ /** Nur nach `--ignore`: so viele Befunde dieses Szenarios wurden ausgenommen (bei Status «bestanden» alle). */
221
+ ignoredFindings: z.ZodOptional<z.ZodNumber>;
221
222
  }, "strip", z.ZodTypeAny, {
222
223
  targetUrl: string;
223
224
  status: "passed" | "suspicious" | "not-checkable" | "not-applicable";
@@ -265,11 +266,12 @@ declare const EvidenceRecordSchema: z.ZodObject<{
265
266
  } | undefined;
266
267
  residualAfterRevoke?: string[] | undefined;
267
268
  screenshots?: {
268
- at: string;
269
269
  path: string;
270
+ at: string;
270
271
  label: string;
271
272
  }[] | undefined;
272
273
  screenshotPath?: string | undefined;
274
+ ignoredFindings?: number | undefined;
273
275
  }, {
274
276
  targetUrl: string;
275
277
  status: "passed" | "suspicious" | "not-checkable" | "not-applicable";
@@ -317,11 +319,12 @@ declare const EvidenceRecordSchema: z.ZodObject<{
317
319
  } | undefined;
318
320
  residualAfterRevoke?: string[] | undefined;
319
321
  screenshots?: {
320
- at: string;
321
322
  path: string;
323
+ at: string;
322
324
  label: string;
323
325
  }[] | undefined;
324
326
  screenshotPath?: string | undefined;
327
+ ignoredFindings?: number | undefined;
325
328
  }>;
326
329
  type EvidenceRecord = z.infer<typeof EvidenceRecordSchema>;
327
330
  /**
@@ -338,8 +341,13 @@ declare const TrackerViolationSchema: z.ZodObject<{
338
341
  trackerName: z.ZodString;
339
342
  trackerCategory: z.ZodEnum<["analytics", "marketing", "functional", "unknown"]>;
340
343
  requestUrl: z.ZodString;
341
- /** Verletzte Regel — steuert Gate-Wortlaut und Empfehlungen */
344
+ /**
345
+ * Verletzte Regel — steuert Gate-Wortlaut und Empfehlungen
346
+ * (u. a. "pre-consent-tracking", "tracking-after-deny", "no-reject-option").
347
+ */
342
348
  ruleId: z.ZodOptional<z.ZodString>;
349
+ /** Hinweis ohne Gate-Wirkung (z. B. rein funktionale Drittanbieter wie Google Fonts) */
350
+ advisory: z.ZodOptional<z.ZodBoolean>;
343
351
  method: z.ZodDefault<z.ZodString>;
344
352
  timestamp: z.ZodString;
345
353
  domContext: z.ZodOptional<z.ZodObject<{
@@ -366,6 +374,7 @@ declare const TrackerViolationSchema: z.ZodObject<{
366
374
  timestamp: string;
367
375
  description: string;
368
376
  ruleId?: string | undefined;
377
+ advisory?: boolean | undefined;
369
378
  domContext?: {
370
379
  triggerElement?: string | undefined;
371
380
  consentBannerVisible?: boolean | undefined;
@@ -380,6 +389,7 @@ declare const TrackerViolationSchema: z.ZodObject<{
380
389
  timestamp: string;
381
390
  description: string;
382
391
  ruleId?: string | undefined;
392
+ advisory?: boolean | undefined;
383
393
  method?: string | undefined;
384
394
  domContext?: {
385
395
  triggerElement?: string | undefined;
@@ -402,8 +412,13 @@ declare const LeakReportSchema: z.ZodObject<{
402
412
  trackerName: z.ZodString;
403
413
  trackerCategory: z.ZodEnum<["analytics", "marketing", "functional", "unknown"]>;
404
414
  requestUrl: z.ZodString;
405
- /** Verletzte Regel — steuert Gate-Wortlaut und Empfehlungen */
415
+ /**
416
+ * Verletzte Regel — steuert Gate-Wortlaut und Empfehlungen
417
+ * (u. a. "pre-consent-tracking", "tracking-after-deny", "no-reject-option").
418
+ */
406
419
  ruleId: z.ZodOptional<z.ZodString>;
420
+ /** Hinweis ohne Gate-Wirkung (z. B. rein funktionale Drittanbieter wie Google Fonts) */
421
+ advisory: z.ZodOptional<z.ZodBoolean>;
407
422
  method: z.ZodDefault<z.ZodString>;
408
423
  timestamp: z.ZodString;
409
424
  domContext: z.ZodOptional<z.ZodObject<{
@@ -430,6 +445,7 @@ declare const LeakReportSchema: z.ZodObject<{
430
445
  timestamp: string;
431
446
  description: string;
432
447
  ruleId?: string | undefined;
448
+ advisory?: boolean | undefined;
433
449
  domContext?: {
434
450
  triggerElement?: string | undefined;
435
451
  consentBannerVisible?: boolean | undefined;
@@ -444,6 +460,7 @@ declare const LeakReportSchema: z.ZodObject<{
444
460
  timestamp: string;
445
461
  description: string;
446
462
  ruleId?: string | undefined;
463
+ advisory?: boolean | undefined;
447
464
  method?: string | undefined;
448
465
  domContext?: {
449
466
  triggerElement?: string | undefined;
@@ -593,17 +610,19 @@ declare const LeakReportSchema: z.ZodObject<{
593
610
  path: z.ZodString;
594
611
  at: z.ZodString;
595
612
  }, "strip", z.ZodTypeAny, {
596
- at: string;
597
613
  path: string;
614
+ at: string;
598
615
  label: string;
599
616
  }, {
600
- at: string;
601
617
  path: string;
618
+ at: string;
602
619
  label: string;
603
620
  }>, "many">>;
604
621
  screenshotPath: z.ZodOptional<z.ZodString>;
605
622
  targetUrl: z.ZodString;
606
623
  checkedAt: z.ZodString;
624
+ /** Nur nach `--ignore`: so viele Befunde dieses Szenarios wurden ausgenommen (bei Status «bestanden» alle). */
625
+ ignoredFindings: z.ZodOptional<z.ZodNumber>;
607
626
  }, "strip", z.ZodTypeAny, {
608
627
  targetUrl: string;
609
628
  status: "passed" | "suspicious" | "not-checkable" | "not-applicable";
@@ -651,11 +670,12 @@ declare const LeakReportSchema: z.ZodObject<{
651
670
  } | undefined;
652
671
  residualAfterRevoke?: string[] | undefined;
653
672
  screenshots?: {
654
- at: string;
655
673
  path: string;
674
+ at: string;
656
675
  label: string;
657
676
  }[] | undefined;
658
677
  screenshotPath?: string | undefined;
678
+ ignoredFindings?: number | undefined;
659
679
  }, {
660
680
  targetUrl: string;
661
681
  status: "passed" | "suspicious" | "not-checkable" | "not-applicable";
@@ -703,12 +723,59 @@ declare const LeakReportSchema: z.ZodObject<{
703
723
  } | undefined;
704
724
  residualAfterRevoke?: string[] | undefined;
705
725
  screenshots?: {
706
- at: string;
707
726
  path: string;
727
+ at: string;
708
728
  label: string;
709
729
  }[] | undefined;
710
730
  screenshotPath?: string | undefined;
731
+ ignoredFindings?: number | undefined;
711
732
  }>, "many">>;
733
+ /** Per `--ignore` gefilterte Befunde — werden ausgewiesen, nicht verschwiegen. */
734
+ ignored: z.ZodOptional<z.ZodArray<z.ZodObject<{
735
+ trackerName: z.ZodString;
736
+ requestUrl: z.ZodString;
737
+ scenario: z.ZodEnum<["happy-path-denied", "happy-path-accepted", "fast-click", "state-manipulation", "network-drop", "consent-revoked", "category-selective", "consent-persistence", "banner-ignored", "subpage-spa", "cmp-failure", "embed-leaks", "consent-mode-v2", "duplicate-events", "mobile-usability"]>;
738
+ pattern: z.ZodString;
739
+ }, "strip", z.ZodTypeAny, {
740
+ trackerName: string;
741
+ scenario: "happy-path-denied" | "happy-path-accepted" | "fast-click" | "state-manipulation" | "network-drop" | "consent-revoked" | "category-selective" | "consent-persistence" | "banner-ignored" | "subpage-spa" | "cmp-failure" | "embed-leaks" | "consent-mode-v2" | "duplicate-events" | "mobile-usability";
742
+ requestUrl: string;
743
+ pattern: string;
744
+ }, {
745
+ trackerName: string;
746
+ scenario: "happy-path-denied" | "happy-path-accepted" | "fast-click" | "state-manipulation" | "network-drop" | "consent-revoked" | "category-selective" | "consent-persistence" | "banner-ignored" | "subpage-spa" | "cmp-failure" | "embed-leaks" | "consent-mode-v2" | "duplicate-events" | "mobile-usability";
747
+ requestUrl: string;
748
+ pattern: string;
749
+ }>, "many">>;
750
+ /**
751
+ * Scanner: wurde irgendwo ein Consent-Banner-Element sichtbar gesehen (auch wenn Accept/Reject nicht klickbar
752
+ * erkannt wurden)? `false` = Suche endete vollständig ohne Banner-Hinweis; `undefined` = nicht ermittelt.
753
+ */
754
+ bannerObserved: z.ZodOptional<z.ZodBoolean>;
755
+ /** Scanner: Hinweise zur Reichweite des Scans (ungültige/ungenutzte Override-Selektoren, spät erschienener Banner). */
756
+ scannerWarnings: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
757
+ /**
758
+ * Szenario `subpage-spa`: so viele der verlinkten Unterseiten wurden geprüft (`checked`, HTTP < 400) von allen
759
+ * verlinkten (`linked`); `max` ist die Obergrenze der Stichprobe (`--max-subpages`). Fehlt, wenn das Szenario nicht lief.
760
+ */
761
+ subpageSampling: z.ZodOptional<z.ZodObject<{
762
+ checked: z.ZodNumber;
763
+ linked: z.ZodNumber;
764
+ max: z.ZodNumber;
765
+ }, "strip", z.ZodTypeAny, {
766
+ checked: number;
767
+ linked: number;
768
+ max: number;
769
+ }, {
770
+ checked: number;
771
+ linked: number;
772
+ max: number;
773
+ }>>;
774
+ /**
775
+ * Warum «kein Banner» nicht belegt ist: `unstable` (Reload-Schleife, Banner nicht auswertbar), `late` (Banner erschien
776
+ * nach dem Wartefenster), `inoperable` (Banner vorhanden, aber nicht über Ablehnen/Akzeptieren bedienbar).
777
+ */
778
+ bannerIssue: z.ZodOptional<z.ZodEnum<["unstable", "late", "inoperable"]>>;
712
779
  }, "strip", z.ZodTypeAny, {
713
780
  targetUrl: string;
714
781
  scannedAt: string;
@@ -724,6 +791,7 @@ declare const LeakReportSchema: z.ZodObject<{
724
791
  timestamp: string;
725
792
  description: string;
726
793
  ruleId?: string | undefined;
794
+ advisory?: boolean | undefined;
727
795
  domContext?: {
728
796
  triggerElement?: string | undefined;
729
797
  consentBannerVisible?: boolean | undefined;
@@ -780,12 +848,27 @@ declare const LeakReportSchema: z.ZodObject<{
780
848
  } | undefined;
781
849
  residualAfterRevoke?: string[] | undefined;
782
850
  screenshots?: {
783
- at: string;
784
851
  path: string;
852
+ at: string;
785
853
  label: string;
786
854
  }[] | undefined;
787
855
  screenshotPath?: string | undefined;
856
+ ignoredFindings?: number | undefined;
857
+ }[] | undefined;
858
+ ignored?: {
859
+ trackerName: string;
860
+ scenario: "happy-path-denied" | "happy-path-accepted" | "fast-click" | "state-manipulation" | "network-drop" | "consent-revoked" | "category-selective" | "consent-persistence" | "banner-ignored" | "subpage-spa" | "cmp-failure" | "embed-leaks" | "consent-mode-v2" | "duplicate-events" | "mobile-usability";
861
+ requestUrl: string;
862
+ pattern: string;
788
863
  }[] | undefined;
864
+ bannerObserved?: boolean | undefined;
865
+ scannerWarnings?: string[] | undefined;
866
+ subpageSampling?: {
867
+ checked: number;
868
+ linked: number;
869
+ max: number;
870
+ } | undefined;
871
+ bannerIssue?: "unstable" | "late" | "inoperable" | undefined;
789
872
  }, {
790
873
  targetUrl: string;
791
874
  scannedAt: string;
@@ -800,6 +883,7 @@ declare const LeakReportSchema: z.ZodObject<{
800
883
  timestamp: string;
801
884
  description: string;
802
885
  ruleId?: string | undefined;
886
+ advisory?: boolean | undefined;
803
887
  method?: string | undefined;
804
888
  domContext?: {
805
889
  triggerElement?: string | undefined;
@@ -857,14 +941,31 @@ declare const LeakReportSchema: z.ZodObject<{
857
941
  } | undefined;
858
942
  residualAfterRevoke?: string[] | undefined;
859
943
  screenshots?: {
860
- at: string;
861
944
  path: string;
945
+ at: string;
862
946
  label: string;
863
947
  }[] | undefined;
864
948
  screenshotPath?: string | undefined;
949
+ ignoredFindings?: number | undefined;
865
950
  }[] | undefined;
951
+ ignored?: {
952
+ trackerName: string;
953
+ scenario: "happy-path-denied" | "happy-path-accepted" | "fast-click" | "state-manipulation" | "network-drop" | "consent-revoked" | "category-selective" | "consent-persistence" | "banner-ignored" | "subpage-spa" | "cmp-failure" | "embed-leaks" | "consent-mode-v2" | "duplicate-events" | "mobile-usability";
954
+ requestUrl: string;
955
+ pattern: string;
956
+ }[] | undefined;
957
+ bannerObserved?: boolean | undefined;
958
+ scannerWarnings?: string[] | undefined;
959
+ subpageSampling?: {
960
+ checked: number;
961
+ linked: number;
962
+ max: number;
963
+ } | undefined;
964
+ bannerIssue?: "unstable" | "late" | "inoperable" | undefined;
866
965
  }>;
966
+ type BannerIssue = NonNullable<z.infer<typeof LeakReportSchema>["bannerIssue"]>;
867
967
  type LeakReport = z.infer<typeof LeakReportSchema>;
968
+ type IgnoredFinding = NonNullable<LeakReport["ignored"]>[number];
868
969
  /**
869
970
  * Patch proposal produced by the remediation engine
870
971
  */
@@ -933,6 +1034,17 @@ declare const ReviewVerdictSchema: z.ZodObject<{
933
1034
  originalContent?: string | undefined;
934
1035
  diff?: string | undefined;
935
1036
  }>, "many">;
1037
+ /** Teilfix: Score und `passed` gelten nur für den gepatchten Teil (`covered` von `total` gemeldeten Trackern). */
1038
+ partial: z.ZodOptional<z.ZodObject<{
1039
+ covered: z.ZodNumber;
1040
+ total: z.ZodNumber;
1041
+ }, "strip", z.ZodTypeAny, {
1042
+ covered: number;
1043
+ total: number;
1044
+ }, {
1045
+ covered: number;
1046
+ total: number;
1047
+ }>>;
936
1048
  }, "strip", z.ZodTypeAny, {
937
1049
  passed: boolean;
938
1050
  score: number;
@@ -951,6 +1063,10 @@ declare const ReviewVerdictSchema: z.ZodObject<{
951
1063
  originalContent?: string | undefined;
952
1064
  diff?: string | undefined;
953
1065
  }[];
1066
+ partial?: {
1067
+ covered: number;
1068
+ total: number;
1069
+ } | undefined;
954
1070
  }, {
955
1071
  passed: boolean;
956
1072
  score: number;
@@ -969,6 +1085,10 @@ declare const ReviewVerdictSchema: z.ZodObject<{
969
1085
  originalContent?: string | undefined;
970
1086
  diff?: string | undefined;
971
1087
  }[];
1088
+ partial?: {
1089
+ covered: number;
1090
+ total: number;
1091
+ } | undefined;
972
1092
  }>;
973
1093
  type ReviewVerdict = z.infer<typeof ReviewVerdictSchema>;
974
1094
  /**
@@ -1060,6 +1180,17 @@ declare const RemediationResultSchema: z.ZodObject<{
1060
1180
  originalContent?: string | undefined;
1061
1181
  diff?: string | undefined;
1062
1182
  }>, "many">;
1183
+ /** Teilfix: Score und `passed` gelten nur für den gepatchten Teil (`covered` von `total` gemeldeten Trackern). */
1184
+ partial: z.ZodOptional<z.ZodObject<{
1185
+ covered: z.ZodNumber;
1186
+ total: z.ZodNumber;
1187
+ }, "strip", z.ZodTypeAny, {
1188
+ covered: number;
1189
+ total: number;
1190
+ }, {
1191
+ covered: number;
1192
+ total: number;
1193
+ }>>;
1063
1194
  }, "strip", z.ZodTypeAny, {
1064
1195
  passed: boolean;
1065
1196
  score: number;
@@ -1078,6 +1209,10 @@ declare const RemediationResultSchema: z.ZodObject<{
1078
1209
  originalContent?: string | undefined;
1079
1210
  diff?: string | undefined;
1080
1211
  }[];
1212
+ partial?: {
1213
+ covered: number;
1214
+ total: number;
1215
+ } | undefined;
1081
1216
  }, {
1082
1217
  passed: boolean;
1083
1218
  score: number;
@@ -1096,6 +1231,10 @@ declare const RemediationResultSchema: z.ZodObject<{
1096
1231
  originalContent?: string | undefined;
1097
1232
  diff?: string | undefined;
1098
1233
  }[];
1234
+ partial?: {
1235
+ covered: number;
1236
+ total: number;
1237
+ } | undefined;
1099
1238
  }>>;
1100
1239
  commitHash: z.ZodOptional<z.ZodString>;
1101
1240
  commitMessage: z.ZodOptional<z.ZodString>;
@@ -1149,6 +1288,10 @@ declare const RemediationResultSchema: z.ZodObject<{
1149
1288
  originalContent?: string | undefined;
1150
1289
  diff?: string | undefined;
1151
1290
  }[];
1291
+ partial?: {
1292
+ covered: number;
1293
+ total: number;
1294
+ } | undefined;
1152
1295
  } | undefined;
1153
1296
  commitHash?: string | undefined;
1154
1297
  commitMessage?: string | undefined;
@@ -1188,6 +1331,10 @@ declare const RemediationResultSchema: z.ZodObject<{
1188
1331
  originalContent?: string | undefined;
1189
1332
  diff?: string | undefined;
1190
1333
  }[];
1334
+ partial?: {
1335
+ covered: number;
1336
+ total: number;
1337
+ } | undefined;
1191
1338
  } | undefined;
1192
1339
  commitHash?: string | undefined;
1193
1340
  commitMessage?: string | undefined;
@@ -1202,16 +1349,26 @@ declare const RemediationResultSchema: z.ZodObject<{
1202
1349
  error?: string | undefined;
1203
1350
  }>;
1204
1351
  type RemediationResult = z.infer<typeof RemediationResultSchema>;
1352
+ /**
1353
+ * Rechtsräume, die `--jurisdiction` akzeptiert (siehe core/legal/jurisdictions.ts).
1354
+ */
1355
+ declare const JurisdictionCodeSchema: z.ZodEnum<["CH", "EU", "UK", "US-CA", "BR", "ROW"]>;
1205
1356
  /**
1206
1357
  * Privacy Gate CLI & Configuration Options
1207
1358
  */
1208
1359
  declare const GateConfigSchema: z.ZodObject<{
1209
- targetUrl: z.ZodString;
1360
+ targetUrl: z.ZodEffects<z.ZodString, string, string>;
1361
+ /** LLM-Key — wird nur gesetzt, wenn `llmRemediation` aktiv ist (siehe resolveGateConfig). */
1210
1362
  apiKey: z.ZodOptional<z.ZodString>;
1211
1363
  llmProvider: z.ZodDefault<z.ZodEnum<["openai", "anthropic", "gemini"]>>;
1212
1364
  llmModel: z.ZodDefault<z.ZodString>;
1365
+ /** Explizites Opt-in: Quellcode darf zur Patch-Erzeugung an den LLM-Anbieter gesendet werden. */
1366
+ llmRemediation: z.ZodDefault<z.ZodBoolean>;
1367
+ /** Default aus: Auto-Fix schreibt nur, wenn der Aufrufer ihn ausdrücklich anfordert. */
1213
1368
  autoFix: z.ZodDefault<z.ZodBoolean>;
1214
1369
  failOnLeak: z.ZodDefault<z.ZodBoolean>;
1370
+ /** Kernszenarien nicht prüfbar ⇒ Exit 4 (INCONCLUSIVE) statt stiller Freigabe. */
1371
+ failOnUncheckable: z.ZodDefault<z.ZodBoolean>;
1215
1372
  reportOutput: z.ZodDefault<z.ZodString>;
1216
1373
  sourceDir: z.ZodDefault<z.ZodString>;
1217
1374
  gitCommit: z.ZodDefault<z.ZodBoolean>;
@@ -1221,27 +1378,73 @@ declare const GateConfigSchema: z.ZodObject<{
1221
1378
  branchPrefix: z.ZodDefault<z.ZodString>;
1222
1379
  /** Optional: nur diese Szenarien ausführen (leer = alle). Für Tests/CI gezielt. */
1223
1380
  scenarios: z.ZodOptional<z.ZodArray<z.ZodEnum<["happy-path-denied", "happy-path-accepted", "fast-click", "state-manipulation", "network-drop", "consent-revoked", "category-selective", "consent-persistence", "banner-ignored", "subpage-spa", "cmp-failure", "embed-leaks", "consent-mode-v2", "duplicate-events", "mobile-usability"]>, "many">>;
1381
+ /** Rechtsraum, der in Konsole und report.json hervorgehoben wird (der Report führt alle Räume auf). */
1382
+ jurisdiction: z.ZodDefault<z.ZodEnum<["CH", "EU", "UK", "US-CA", "BR", "ROW"]>>;
1224
1383
  /** Demo-Lauf mit synthetischen Testdaten — Report wird gekennzeichnet */
1225
1384
  demo: z.ZodOptional<z.ZodBoolean>;
1226
1385
  /** Deluxe-PDF (Deckblatt + Evidence) nach dem Scan erzeugen */
1227
1386
  reportPdf: z.ZodOptional<z.ZodBoolean>;
1228
- /** Kundenname für das PDF-Deckblatt */
1387
+ /** Kundenname für das PDF-Deckblatt (Default: Host der Ziel-URL) */
1229
1388
  clientName: z.ZodOptional<z.ZodString>;
1230
1389
  headless: z.ZodDefault<z.ZodBoolean>;
1390
+ /** Timeout je Szenario-Navigation und für den Erreichbarkeits-Check (ms) */
1231
1391
  timeoutMs: z.ZodDefault<z.ZodNumber>;
1392
+ /** Hinweise (advisory, z. B. rein funktionale Google Fonts) blockieren das Gate ebenfalls. */
1393
+ strict: z.ZodDefault<z.ZodBoolean>;
1394
+ /** Tracker-Namen oder Host-Muster (`fonts.googleapis.com`, `*.hotjar.com`), die als «ignoriert» ausgewiesen werden. */
1395
+ ignore: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
1396
+ /** Erlaubt sehr breite `--ignore`-Muster (`*`, `*.com`, einzelne TLD); sonst Exit 3. Nur CLI/echte Umgebung. */
1397
+ allowBroadIgnore: z.ZodDefault<z.ZodBoolean>;
1398
+ /** Obergrenze der Unterseiten-Stichprobe (Szenario subpage-spa), `--max-subpages` (Standard 12, höchstens 40). */
1399
+ maxSubpages: z.ZodDefault<z.ZodNumber>;
1400
+ /**
1401
+ * Wartefenster auf einen (spät erscheinenden) Banner in Sekunden, `--banner-wait` (höchstens 60). Ohne Angabe gilt das
1402
+ * bisherige Verhalten (8 s, bei Seiten ohne Banner-Hinweis früher beendet); mit Angabe wird das Fenster ausgeschöpft.
1403
+ */
1404
+ bannerWaitSeconds: z.ZodOptional<z.ZodNumber>;
1405
+ /** Hinweise zur Eingabe (z. B. leerer Selektor), die der Scanner in `scannerWarnings` übernimmt. */
1406
+ configWarnings: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
1407
+ /** Scanner-Overrides für eigene Banner (CSS-Selektoren bzw. Teilstring der Banner-Frame-URL). */
1408
+ acceptSelectors: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
1409
+ rejectSelectors: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
1410
+ settingsSelectors: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
1411
+ bannerFrame: z.ZodOptional<z.ZodString>;
1412
+ /**
1413
+ * Lizenzstatus — wird ausschliesslich von der CLI (oder dem Aufrufer der API) gesetzt, nie aus Env/.env.
1414
+ * Ohne gültige Lizenz laufen PDF-Report, Kundenreport (`client`), `gitCommit` und `createPr` nicht
1415
+ * (Scan und Gate bleiben frei; Loopback-Ziele sind immer frei).
1416
+ */
1417
+ license: z.ZodOptional<z.ZodObject<{
1418
+ entitled: z.ZodBoolean;
1419
+ /** Warum nicht lizenziert: keine Lizenz gesetzt | Lizenzserver nicht erreichbar */
1420
+ reason: z.ZodOptional<z.ZodEnum<["none", "unreachable"]>>;
1421
+ }, "strip", z.ZodTypeAny, {
1422
+ entitled: boolean;
1423
+ reason?: "none" | "unreachable" | undefined;
1424
+ }, {
1425
+ entitled: boolean;
1426
+ reason?: "none" | "unreachable" | undefined;
1427
+ }>>;
1232
1428
  }, "strip", z.ZodTypeAny, {
1233
1429
  targetUrl: string;
1234
1430
  llmProvider: "openai" | "anthropic" | "gemini";
1235
1431
  llmModel: string;
1432
+ llmRemediation: boolean;
1236
1433
  autoFix: boolean;
1237
1434
  failOnLeak: boolean;
1435
+ failOnUncheckable: boolean;
1238
1436
  reportOutput: string;
1239
1437
  sourceDir: string;
1240
1438
  gitCommit: boolean;
1241
1439
  createPr: boolean;
1242
1440
  branchPrefix: string;
1441
+ jurisdiction: "CH" | "EU" | "UK" | "US-CA" | "BR" | "ROW";
1243
1442
  headless: boolean;
1244
1443
  timeoutMs: number;
1444
+ strict: boolean;
1445
+ ignore: string[];
1446
+ allowBroadIgnore: boolean;
1447
+ maxSubpages: number;
1245
1448
  apiKey?: string | undefined;
1246
1449
  githubToken?: string | undefined;
1247
1450
  baseBranch?: string | undefined;
@@ -1249,13 +1452,25 @@ declare const GateConfigSchema: z.ZodObject<{
1249
1452
  demo?: boolean | undefined;
1250
1453
  reportPdf?: boolean | undefined;
1251
1454
  clientName?: string | undefined;
1455
+ bannerWaitSeconds?: number | undefined;
1456
+ configWarnings?: string[] | undefined;
1457
+ acceptSelectors?: string[] | undefined;
1458
+ rejectSelectors?: string[] | undefined;
1459
+ settingsSelectors?: string[] | undefined;
1460
+ bannerFrame?: string | undefined;
1461
+ license?: {
1462
+ entitled: boolean;
1463
+ reason?: "none" | "unreachable" | undefined;
1464
+ } | undefined;
1252
1465
  }, {
1253
1466
  targetUrl: string;
1254
1467
  apiKey?: string | undefined;
1255
1468
  llmProvider?: "openai" | "anthropic" | "gemini" | undefined;
1256
1469
  llmModel?: string | undefined;
1470
+ llmRemediation?: boolean | undefined;
1257
1471
  autoFix?: boolean | undefined;
1258
1472
  failOnLeak?: boolean | undefined;
1473
+ failOnUncheckable?: boolean | undefined;
1259
1474
  reportOutput?: string | undefined;
1260
1475
  sourceDir?: string | undefined;
1261
1476
  gitCommit?: boolean | undefined;
@@ -1264,23 +1479,129 @@ declare const GateConfigSchema: z.ZodObject<{
1264
1479
  baseBranch?: string | undefined;
1265
1480
  branchPrefix?: string | undefined;
1266
1481
  scenarios?: ("happy-path-denied" | "happy-path-accepted" | "fast-click" | "state-manipulation" | "network-drop" | "consent-revoked" | "category-selective" | "consent-persistence" | "banner-ignored" | "subpage-spa" | "cmp-failure" | "embed-leaks" | "consent-mode-v2" | "duplicate-events" | "mobile-usability")[] | undefined;
1482
+ jurisdiction?: "CH" | "EU" | "UK" | "US-CA" | "BR" | "ROW" | undefined;
1267
1483
  demo?: boolean | undefined;
1268
1484
  reportPdf?: boolean | undefined;
1269
1485
  clientName?: string | undefined;
1270
1486
  headless?: boolean | undefined;
1271
1487
  timeoutMs?: number | undefined;
1488
+ strict?: boolean | undefined;
1489
+ ignore?: string[] | undefined;
1490
+ allowBroadIgnore?: boolean | undefined;
1491
+ maxSubpages?: number | undefined;
1492
+ bannerWaitSeconds?: number | undefined;
1493
+ configWarnings?: string[] | undefined;
1494
+ acceptSelectors?: string[] | undefined;
1495
+ rejectSelectors?: string[] | undefined;
1496
+ settingsSelectors?: string[] | undefined;
1497
+ bannerFrame?: string | undefined;
1498
+ license?: {
1499
+ entitled: boolean;
1500
+ reason?: "none" | "unreachable" | undefined;
1501
+ } | undefined;
1272
1502
  }>;
1273
- type GateConfig = z.infer<typeof GateConfigSchema>;
1503
+ /** Geparste Konfiguration (alle Defaults gesetzt). */
1504
+ type GateConfig = z.output<typeof GateConfigSchema>;
1505
+ /** Eingabe-Typ der öffentlichen API: Felder mit Default sind optional. */
1506
+ type GateConfigInput = z.input<typeof GateConfigSchema>;
1507
+ /**
1508
+ * Exit-Codes der CLI (in `--help` dokumentiert).
1509
+ */
1510
+ declare const EXIT: {
1511
+ readonly OK: 0;
1512
+ /** Offene Leaks (BLOCKED), auch bei nur vorgeschlagenem, nicht verifiziertem Fix */
1513
+ readonly LEAKS: 1;
1514
+ /** Lizenz ungültig/abgelaufen/gesperrt (fehlende Lizenz oder nicht erreichbarer Lizenzserver nicht) */
1515
+ readonly LICENSE: 2;
1516
+ /** Fehler: Ziel unerreichbar, Konfiguration, Browser fehlt */
1517
+ readonly ERROR: 3;
1518
+ /** Unvollständig: Kernszenarien nicht prüfbar (INCONCLUSIVE) */
1519
+ readonly INCONCLUSIVE: 4;
1520
+ };
1521
+ /**
1522
+ * Vollständigkeit eines Scans: «nicht prüfbar» ist kein «bestanden».
1523
+ */
1524
+ interface GateAssessment {
1525
+ /** Anzahl der geforderten Szenarien (z. B. 15) */
1526
+ scenariosTotal: number;
1527
+ /** Alle nicht prüfbaren Szenarien (inkl. «auffällig» mit Timeout/Fehler-Aktion) */
1528
+ uncheckable: ChaosScenario[];
1529
+ /** Davon Kernszenarien (Ablehnen-/Akzeptieren-Pfad, die den Banner bedienen) */
1530
+ coreUncheckable: ChaosScenario[];
1531
+ /** true, wenn kein Szenario nicht prüfbar ist und die Unterseiten-Stichprobe vollständig war */
1532
+ complete: boolean;
1533
+ /** Befundgruppen (Ursachen) statt Request-Zeilen — nur gate-blockierende Befunde */
1534
+ findingGroups: {
1535
+ ruleId: string;
1536
+ trackerName: string;
1537
+ count: number;
1538
+ }[];
1539
+ /** Hinweise (advisory), nicht gate-blockierend ausser mit `--strict` */
1540
+ advisoryGroups: {
1541
+ ruleId: string;
1542
+ trackerName: string;
1543
+ count: number;
1544
+ }[];
1545
+ /** Seite ohne Consent-Banner und ohne Tracker: es gibt nichts zu prüfen */
1546
+ noBannerNoTracker: boolean;
1547
+ /** Unterseiten-Stichprobe (Szenario subpage-spa), falls es lief */
1548
+ sampling?: SamplingInfo;
1549
+ }
1550
+ /** Unterseiten-Stichprobe: `checked` von `linked` geprüft; `incomplete`, wenn nicht alle verlinkten Unterseiten dran waren. */
1551
+ interface SamplingInfo {
1552
+ checked: number;
1553
+ linked: number;
1554
+ max: number;
1555
+ incomplete: boolean;
1556
+ }
1557
+ /**
1558
+ * Gate-Zustand: `clean` = PASS, `remediated` = Fix durch sauberen Re-Scan der Ziel-URL verifiziert,
1559
+ * `fix-proposed` = Fix als Commit/PR vorgeschlagen, aber nicht verifiziert (weiterhin BLOCKED).
1560
+ */
1561
+ type GateState = "clean" | "remediated" | "blocked" | "inconclusive" | "fix-proposed";
1562
+ /** Gate-Zustand, wie ihn der Orchestrator führt — Eingabe für Report, Deckblatt und PDF. */
1563
+ interface ReportGate {
1564
+ state: GateState;
1565
+ scenariosTotal: number;
1566
+ /** Anzahl nicht prüfbarer Szenarien (laut Orchestrator) */
1567
+ uncheckable: number;
1568
+ coreUncheckable: ChaosScenario[];
1569
+ /** `--strict`: Hinweise zählen als Verstoss */
1570
+ strict?: boolean;
1571
+ noBannerNoTracker?: boolean;
1572
+ /** Vom Scanner gemeldet: wurde ein Consent-Banner gesehen? (undefined = unbekannt) */
1573
+ bannerObserved?: boolean;
1574
+ /** Warum «kein Banner» nicht belegt ist (Reload-Schleife, spät erschienen, nicht bedienbar) */
1575
+ bannerIssue?: BannerIssue;
1576
+ /** Unterseiten-Stichprobe (Szenario subpage-spa), falls es lief */
1577
+ sampling?: SamplingInfo;
1578
+ /** Warnungen des Scanners (z. B. ungültige Override-Selektoren) */
1579
+ scannerWarnings?: string[];
1580
+ /** `--ignore`-Muster, die sehr breit sind (nur mit `--allow-broad-ignore` überhaupt zulässig oder nur Warnung) */
1581
+ broadIgnore?: string[];
1582
+ /** Teilfix mit Commit/PR: so viele gemeldete Tracker bleiben manuell zu beheben */
1583
+ partialManual?: number;
1584
+ }
1274
1585
  /**
1275
1586
  * Overall pipeline outcome
1276
1587
  */
1277
1588
  interface GateExecutionResult {
1278
1589
  report: LeakReport;
1279
1590
  remediation?: RemediationResult;
1280
- status: "clean" | "remediated" | "blocked" | "error";
1591
+ status: GateState | "error";
1281
1592
  exitCode: number;
1593
+ assessment?: GateAssessment;
1282
1594
  }
1283
1595
 
1596
+ /** Für `--help`: die einzigen Schlüssel, die eine `.env` setzen darf. */
1597
+ declare const ENV_FILE_KEYS_HELP: string;
1598
+ declare function isEnvKeyAllowedFromFile(key: string): boolean;
1599
+ /**
1600
+ * Lädt eine `.env` aus dem Arbeitsverzeichnis in `process.env` — nur explizit aufgerufen (CLI),
1601
+ * nie als Import-Seiteneffekt. Die echte Umgebung gewinnt (wie bei dotenv); übernommen wird nur die Allowlist
1602
+ * (`isEnvKeyAllowedFromFile`).
1603
+ */
1604
+ declare function loadProjectEnv(file?: string, env?: NodeJS.ProcessEnv): void;
1284
1605
  interface CliRawOptions {
1285
1606
  reportPdf?: boolean | string;
1286
1607
  client?: string;
@@ -1289,8 +1610,11 @@ interface CliRawOptions {
1289
1610
  apiKey?: string;
1290
1611
  llmProvider?: string;
1291
1612
  llmModel?: string;
1613
+ /** Opt-in: Quellcode darf an den LLM-Anbieter gesendet werden */
1614
+ llmRemediation?: string | boolean;
1292
1615
  autoFix?: string | boolean;
1293
1616
  failOnLeak?: string | boolean;
1617
+ failOnUncheckable?: string | boolean;
1294
1618
  reportOutput?: string;
1295
1619
  sourceDir?: string;
1296
1620
  gitCommit?: string | boolean;
@@ -1300,128 +1624,311 @@ interface CliRawOptions {
1300
1624
  baseBranch?: string;
1301
1625
  headless?: string | boolean;
1302
1626
  timeoutMs?: string | number;
1627
+ /** Szenarien-Auswahl: Array oder kommagetrennte Liste (leer = alle) */
1628
+ scenarios?: ChaosScenario[] | string[] | string;
1629
+ /** Rechtsraum: CH | EU | UK | US-CA | BR | ROW */
1630
+ jurisdiction?: string;
1631
+ /** Wird hier nicht ausgewertet — die Lizenzprüfung passiert in der CLI (src/cli.ts). */
1632
+ license?: string;
1633
+ /** Hinweise (advisory) blockieren ebenfalls */
1634
+ strict?: string | boolean;
1635
+ /** Sehr breite --ignore-Muster (`*`, `*.com`, einzelne TLD) bewusst erlauben */
1636
+ allowBroadIgnore?: string | boolean;
1637
+ /** Tracker-Namen oder Host-Muster, kommagetrennt oder mehrfach */
1638
+ ignore?: string[] | string;
1639
+ /** Scanner-Overrides: CSS-Selektoren, kommagetrennt oder mehrfach */
1640
+ acceptSelector?: string[] | string;
1641
+ rejectSelector?: string[] | string;
1642
+ settingsSelector?: string[] | string;
1643
+ /** Teilstring der URL des Banner-Frames (iframe-CMP) */
1644
+ bannerFrame?: string;
1645
+ /** Obergrenze der Unterseiten-Stichprobe (Standard 12, höchstens 40) */
1646
+ maxSubpages?: string | number;
1647
+ /** Wartefenster auf einen spät erscheinenden Banner in Sekunden (höchstens 60) */
1648
+ bannerWait?: string | number;
1303
1649
  }
1650
+ /** Validiert eine Eingabe (Defaults werden gesetzt). Wirft «Invalid Configuration». */
1651
+ declare function parseGateConfig(input: GateConfigInput): GateConfig;
1304
1652
  declare function resolveGateConfig(cliOptions: CliRawOptions): GateConfig;
1305
1653
 
1306
1654
  interface ChaosScannerInterface {
1307
1655
  scan(config: GateConfig): Promise<LeakReport>;
1308
1656
  }
1309
1657
 
1310
- /**
1311
- * True when `pageUrl` is still on the scanned target origin (or not yet navigated).
1312
- * Used so tracker traffic from off-site navigation (e.g. a logo link to a vendor site)
1313
- * is not attributed to the target under test.
1314
- */
1315
- declare function isOnTargetOrigin(pageUrl: string, targetOrigin: string): boolean;
1316
- /**
1317
- * Clicks the first anchor whose resolved URL stays on `targetOrigin`.
1318
- * Off-site links (logo/footer/vendor) are skipped to avoid leaving the page under test.
1319
- */
1320
- declare function clickFirstSameOriginLink(page: playwright.Page, targetOrigin: string): Promise<boolean>;
1658
+ /** Optionale Vorgaben fuer Seiten mit unbekanntem Banner; werden VOR den Standardlisten ausgewertet. */
1659
+ interface ScannerOverrides {
1660
+ /** CSS-/Playwright-Selektoren fuer «Alle akzeptieren». */
1661
+ acceptSelectors?: string[];
1662
+ /** CSS-/Playwright-Selektoren fuer «Ablehnen» / «Nur notwendige». */
1663
+ rejectSelectors?: string[];
1664
+ /** CSS-/Playwright-Selektoren fuer «Einstellungen». */
1665
+ settingsSelectors?: string[];
1666
+ /** Teilstring der Frame-URL, in der der Banner liegt (cross-origin iframe-CMP). */
1667
+ bannerFrame?: string;
1668
+ /**
1669
+ * Das Wartefenster ausschöpfen, statt bei Seiten ohne Banner-Hinweis früh aufzugeben (`--banner-wait`). Gilt auch
1670
+ * ohne diese Angabe, sobald eigene Selektoren oder ein Banner-Frame angegeben sind: dann wird bis zum Ende gewartet.
1671
+ */
1672
+ exhaustiveWait?: boolean;
1673
+ }
1674
+
1675
+ interface ChaosScannerOptions extends ScannerOverrides {
1676
+ /** Zielverzeichnis fuer Screenshots (Default: `evidence/` neben dem Report aus der Config). */
1677
+ evidenceDir?: string;
1678
+ /** Obergrenze fuer die Gesamtgroesse der Screenshots eines Laufs in Bytes (Default 100 MB); darueber nur noch verkleinerte. */
1679
+ evidenceMaxBytes?: number;
1680
+ }
1321
1681
  declare class ChaosScanner implements ChaosScannerInterface {
1682
+ private evidenceDir?;
1683
+ private readonly overrides;
1684
+ /** Bannersuche des laufenden Scans (Selektoren inkl. Overrides, «kein Banner» gemerkt). */
1685
+ private session;
1686
+ /** Navigation je Szenario (Fail-open-Schutz: Seite endete auf fremder Origin). */
1687
+ private watches;
1688
+ /** GTM-/gtag-Loader mit Consent Mode (default denied) ohne Messung ist kein Pre-Consent-Leak. */
1689
+ private gtmLoaderExempt;
1690
+ /** Hinweise zur Reichweite des Scans (Selektor-Fehler, spaet erschienener oder nicht bedienbarer Banner). */
1691
+ private warnings;
1692
+ /** Wartefenster auf einen Banner (ms) und ob es ausdruecklich gesetzt wurde (`--banner-wait`). */
1693
+ private bannerWaitMs;
1694
+ private bannerWaitExplicit;
1695
+ /** Obergrenze der Unterseiten-Stichprobe (`--max-subpages`). */
1696
+ private maxSubpages;
1697
+ /** Ergebnis der Schlusspruefung: nur `completed` belegt «kein Banner». */
1698
+ private bannerProbe;
1699
+ private bannerIssue?;
1700
+ private subpageSampling?;
1701
+ /** Bytes der in diesem Lauf geschriebenen Screenshots und deren Obergrenze. */
1702
+ private evidenceBytes;
1703
+ private evidenceCapNoted;
1704
+ private readonly evidenceMaxBytes;
1705
+ constructor(options?: ChaosScannerOptions);
1706
+ /** Die Schlusspruefung lief das Wartefenster vollstaendig ohne Banner-Hinweis durch (Seite stabil). */
1707
+ private probeCompleted;
1708
+ /** Overrides plus: das Wartefenster ausschoepfen, wenn `--banner-wait` ausdruecklich gesetzt ist. */
1709
+ private sessionOverrides;
1710
+ /** Beobachtung der Hauptseiten-Navigation fuer `scenario` merken (nachtraegliche Bewertung in scan()). */
1711
+ private remember;
1712
+ /** Verhalten eines erkannten Trackers: kein Befund (GTM-Loader mit Consent Mode), Hinweis oder Verstoss. */
1713
+ private trackerVerdict;
1714
+ /** `{ advisory: true }` fuer rein funktionale Treffer (Hinweis ohne Gate-Wirkung). */
1715
+ private advisoryFlag;
1716
+ /** Zaehlt ein Timeline-Ereignis als belastbarer Tracker-Befund (nicht advisory, nicht exempt). */
1717
+ private isBlocking;
1322
1718
  scan(config: GateConfig): Promise<LeakReport>;
1719
+ /** Browser-Kontext mit blockierten Service Workern (deren Requests waeren unsichtbar) und Registrierungs-Beobachtung. */
1720
+ private newContext;
1721
+ /** Ungueltige Override-Selektoren (CSS-Syntaxfehler) werden gemeldet statt still verschluckt. */
1722
+ private checkOverrideSelectors;
1723
+ /**
1724
+ * Schlusspruefung: War bis hierhin kein Banner sichtbar, laedt ein frischer Kontext die Zielseite und wartet
1725
+ * ueber das normale Wartefenster hinaus. Erscheint ein Banner erst spaeter (Timer, langsames CMP), gilt
1726
+ * «kein Banner» nicht — `bannerObserved` wird `true`, mit Hinweis.
1727
+ */
1728
+ private probeLateBanner;
1729
+ /** Hinweise zum Banner-Zustand und zu nie verwendeten Override-Selektoren in `scannerWarnings`. */
1730
+ private reportBannerState;
1323
1731
  private snapshotStorage;
1732
+ /**
1733
+ * Navigiert zur Ziel-URL und fuehrt den Zielbereich nach: die finale URL (nach Redirects)
1734
+ * gehoert zum Ziel, auch wenn sie auf einer anderen Origin liegt. Navigiert die Seite selbst
1735
+ * weiter (`<meta refresh>`, `location.replace`), wird auf die neue Seite gewartet statt abzubrechen.
1736
+ * Fehlermeldungen nennen die konfigurierte Ursprungs-URL, nicht nur das Weiterleitungsziel.
1737
+ */
1738
+ private gotoTarget;
1739
+ /**
1740
+ * Scanner-Navigation zu einer verlinkten Unterseite: deren Weiterleitungen erweitern den Zielbereich nicht.
1741
+ * Laufende Navigationen der vorigen Seite werden abgewartet; leitet die Unterseite selbst clientseitig weiter
1742
+ * («interrupted by another navigation»), gilt der HTTP-Status der Endseite statt eines Abbruchs.
1743
+ */
1744
+ private gotoSubpage;
1745
+ /**
1746
+ * Consent Mode: Setzt die Seite VOR dem GTM-/gtag-Laden `consent default denied` und findet vor
1747
+ * Consent keine Messung statt (keine Collect-/Pixel-Requests, keine Tracking-Cookies), ist der reine
1748
+ * Skript-Load des Loaders kein Pre-Consent-Leak. Ohne Consent Mode bleibt er ein Verstoss.
1749
+ */
1750
+ private probeGtmConsentMode;
1751
+ /** Rein funktionale Drittanbieter (z. B. Google Fonts) in der Timeline: als Hinweis in der Notiz vermerken. */
1752
+ private annotateAdvisory;
1753
+ /** Steht (jetzt) irgendein Consent-Banner im DOM der Zielseite? Merkt es fuer `bannerObserved`. */
1754
+ private noteBannerHints;
1755
+ /**
1756
+ * Fail-open-Schutz: Lief ein Szenario ganz oder teilweise auf einer fremden Seite (Requests wurden
1757
+ * dem Ziel nicht zugerechnet), ist ein «bestanden» nicht belastbar — dann «nicht prüfbar» mit Begruendung.
1758
+ */
1759
+ private applyScopeVerdicts;
1324
1760
  /**
1325
1761
  * Fünf Kern-Chaos-Szenarien mit vollständigem Evidence-Record.
1326
1762
  * Phasen statt Capture-Wipe: Pre-Consent-Funde bleiben immer erhalten.
1327
1763
  * Ergebnis: passed nur bei ausgeführter Aktion und null Illegal-Funden.
1328
1764
  */
1329
1765
  private runScenario;
1766
+ /**
1767
+ * Kein Ablehnen-Button gefunden: ist das ein Dark Pattern oder nur ein nicht erkannter Banner?
1768
+ * Sehr konservativ — «Banner nicht erkannt» wird nie als Dark Pattern gemeldet. Ein Befund
1769
+ * (`no-reject-option`) entsteht nur, wenn (1) auf der ersten Ebene ein Accept erkannt ist,
1770
+ * (2) der Banner eindeutig als Cookie-Dialog erkennbar ist und ausser Accept nur Einstellungen/
1771
+ * Infolinks enthaelt, (3) auch die Einstellungen (zweite Ebene) keinen Ablehnen-Weg bieten und
1772
+ * (4) Tracking im Spiel ist (vor der Entscheidung oder nach dem Akzeptieren).
1773
+ * `rejected`: ein Ablehnen-Weg wurde auf der zweiten Ebene gefunden und geklickt.
1774
+ */
1775
+ private assessMissingReject;
1330
1776
  private snap;
1331
- private logAct;
1332
1777
  /**
1333
- * Widerruf: erst akzeptieren, dann widerrufen. Prüft (a) keine neuen Tracker-Requests
1334
- * nach Widerruf, (b) ob Tracking-IDs in Cookies/Storage zurückbleiben.
1335
- * Kein Widerruf-Button — status «not-checkable» (nie grün).
1778
+ * Screenshot fuer den Evidence-Ordner: Breite = Viewport, hoechstens SHOT_MAX_HEIGHT hoch, JPEG. Bleibt die Datei ueber
1779
+ * SHOT_MAX_BYTES, wird mit sinkender Qualitaet und Hoehe erneut aufgenommen. Ist der evidence-Ordner des Laufs voll
1780
+ * (evidenceMaxBytes), entstehen nur noch verkleinerte Aufnahmen, mit Hinweis in den Scanner-Warnungen.
1336
1781
  */
1782
+ private captureShot;
1783
+ /** Bricht eine noch laufende Navigation ab (Chrome `Page.stopLoading`), ohne auf deren Antwort zu warten. */
1784
+ private stopLoading;
1785
+ private logAct;
1337
1786
  /**
1338
1787
  * Kategorien-Granularität: Statistik erlaubt, Marketing abgelehnt.
1339
- * Marketing-Tracker (Meta, TikTok, LinkedIn, Criteo ⬦) dürfen danach NICHT feuern.
1340
- * Keine Kategorie-UI — status «not-checkable».
1788
+ * Marketing-Tracker (Meta, TikTok, LinkedIn, Criteo, …) dürfen danach NICHT feuern.
1789
+ * Ohne Kategorie-UI, ohne belegt abgewähltes Marketing oder ohne Speichern-Button —
1790
+ * status «not-checkable» (nie «Alle akzeptieren» als Ersatz).
1341
1791
  */
1342
1792
  private runCategorySelectiveScenario;
1343
1793
  /**
1344
- * Entscheidung merken: nach «Ablehnen» Reload, Unterseiten-URL und Browser-Neustart
1345
- * (storageState). Tracker müssen ausbleiben, die Entscheidung muss erhalten bleiben.
1794
+ * Entscheidung merken: nach «Ablehnen» Reload, Unterseite (echter verlinkter Pfad) und
1795
+ * Browser-Neustart (storageState). Tracker müssen ausbleiben, die Entscheidung muss erhalten
1796
+ * bleiben. Ohne erreichbare Unterseite ist die Persistenz nicht vollständig belegt — «not-checkable».
1346
1797
  */
1347
1798
  private runPersistenceScenario;
1348
1799
  /**
1349
- * Banner ignorieren: kein Klick, nur warten, scrollen, Navigation.
1350
- * Tracker dürfen nicht über Timer/Scroll/Input allein starten.
1351
- */
1352
- /**
1353
- * Unterseiten & SPA: Direkteinstieg auf Subpage, dann Client-Navigation ohne Reload.
1354
- * Consent-Schutz muss auch dort greifen.
1355
- */
1356
- /**
1357
- * CMP langsam oder defekt: CMP-Skripte verzögern/abbringen, dann beobachten,
1358
- * ob im Zeitfenster Tracker starten (Default-State-Leak).
1800
+ * Mobile: iPhone-Viewport. Reject und Settings müssen sichtbar und klickbar sein.
1801
+ * Nur Accept bedienbar — suspicious (Dark Pattern); keine Buttons — not-checkable.
1359
1802
  */
1803
+ private runMobileUsabilityScenario;
1360
1804
  /**
1361
- * Eingebettete Inhalte (YouTube, Maps, Social, Chat): Drittanbieter-Requests
1362
- * vor Consent-Freigabe des Embeds. Inklusive iframe-src und nachgeladenen SDKs.
1805
+ * Doppelte Events: ein Seitenaufruf nach Consent darf page_view nicht doppelt zählen
1806
+ * (Plugin + GTM parallel) — je Property (GA4 `tid`, Pixel `id`, …): mehrere Properties mit je
1807
+ * einem Beacon sind kein Duplikat. Ohne belegten Accept-Klick ist der Consent-Zustand nicht
1808
+ * hergestellt — «not-checkable». First-Party-Heuristik: verdächtige same-origin Endpunkte
1809
+ * (collect, pixel, track) werden markiert — Server-zu-Server ist von aussen begrenzt beweisbar.
1363
1810
  */
1811
+ private runDuplicateEventsScenario;
1364
1812
  /**
1365
- * Consent Mode v2: dataLayer-Konsens-Zustände (ad_storage, analytics_storage, ⬦)
1813
+ * Consent Mode v2: dataLayer-Konsens-Zustände (ad_storage, analytics_storage, …)
1366
1814
  * gegen tatsächliche Google-Requests und Cookies trennen.
1367
1815
  * Bei Basic dürfen nach Ablehnung keine Nutzungsdaten laufen; bei Advanced
1368
1816
  * sind cookielose Pings möglich — beides wird getrennt ausgewiesen.
1369
1817
  */
1818
+ private runConsentModeV2Scenario;
1370
1819
  /**
1371
- * Doppelte Events: ein Seitenaufruf nach Consent darf page_view nicht doppelt zählen
1372
- * (Plugin + GTM parallel). First-Party-Heuristik: verdächtige same-origin Endpunkte
1373
- * (collect, pixel, track) werden markiert — Server-zu-Server ist von aussen begrenzt beweisbar.
1820
+ * Eingebettete Inhalte (YouTube, Maps, Social): Drittanbieter-Requests vor Consent-Freigabe
1821
+ * des Embeds. Als Embed gilt nur, was die Tracker-Datenbank als Embed-Kategorie fuehrt —
1822
+ * nicht per Namens-Regex (sonst wuerde z. B. das Meta Pixel als «Embed» klassifiziert).
1374
1823
  */
1824
+ private runEmbedScenario;
1375
1825
  /**
1376
- * Mobile: iPhone-Viewport. Reject und Settings müssen sichtbar und klickbar sein.
1377
- * Nur Accept bedienbar — suspicious (Dark Pattern); keine Buttons — not-checkable.
1826
+ * CMP langsam oder defekt: CMP-Ressourcen (auch same-origin, self-hosted) verzögern, dann
1827
+ * hart abbrechen, und beobachten, ob im Zeitfenster Tracker starten (Default-State-Leak).
1828
+ * Ohne abgefangene CMP-Ressource gibt es keinen Nachweis eines verzögerten CMPs —
1829
+ * dann «not-checkable» statt «passed».
1378
1830
  */
1379
- private runMobileUsabilityScenario;
1380
- private runDuplicateEventsScenario;
1381
- private runConsentModeV2Scenario;
1382
- private runEmbedScenario;
1383
1831
  private runCmpFailureScenario;
1832
+ /** Seite, auf der ein Request ausgelöst wurde (für Befunde auf Unterseiten); leer, wenn nicht ermittelbar. */
1833
+ private pageHint;
1834
+ /**
1835
+ * Unterseiten & SPA: echte, auf der Startseite verlinkte Same-Origin-Pfade (HTTP-Status geprüft)
1836
+ * als Direkteinstieg, danach clientseitige Navigation (Link-Klick ohne Dokument-Reload,
1837
+ * History-API) beobachten. Es wird kein Consent erteilt — jeder Tracker ist ein Verstoss.
1838
+ * Ohne erreichbare verlinkte Unterseite «not-checkable» (erfundene Pfade ergeben keinen Beleg).
1839
+ */
1384
1840
  private runSubpageSpaScenario;
1841
+ /**
1842
+ * Banner ignorieren: kein Klick auf den Banner, nur warten, scrollen, auf freie Flaeche tippen.
1843
+ * Tracker dürfen nicht über Timer/Scroll/Input allein starten.
1844
+ */
1385
1845
  private runBannerIgnoredScenario;
1846
+ /**
1847
+ * Widerruf: erst akzeptieren, dann widerrufen. Prüft (a) keine neuen Tracker-Requests
1848
+ * nach Widerruf, (b) ob Tracking-IDs in Cookies/Storage zurückbleiben.
1849
+ * Kein Widerruf-Button — status «not-checkable» (nie grün).
1850
+ */
1386
1851
  private runRevocationScenario;
1387
1852
  }
1388
1853
 
1854
+ /** patched = no unguarded execution left; manual = an auto-fix exists but could not be applied here; unpatched = no auto-fix. */
1855
+ type TrackerPatchState = "patched" | "unpatched" | "manual";
1856
+ interface TrackerStatus {
1857
+ trackerName: string;
1858
+ state: TrackerPatchState;
1859
+ /** Why the tracker is not (fully) patched, or what was done; German, shown to the user. */
1860
+ reason?: string;
1861
+ }
1862
+ /**
1863
+ * RemediationResult plus what the caller needs to stay honest about partial fixes. Structurally a
1864
+ * RemediationResult (all additions are optional), so existing consumers keep working.
1865
+ */
1866
+ interface RemediationOutcome extends RemediationResult {
1867
+ /**
1868
+ * Also set for a partial fix (`partial: true`, `success: false`) whenever the approved patches were committed or
1869
+ * pushed: `commitHash` (short hash of the commit, `gitCommit`), `pullRequest` (PR result incl. `branchName`, `createPr`)
1870
+ * and `branchName` (the fix branch of the PR, a copy of `pullRequest.branchName`). A consumer must not read
1871
+ * `success` as "nothing was written": check these fields.
1872
+ */
1873
+ branchName?: string;
1874
+ /** Some patches were applied, but not every reported tracker is covered: do NOT treat the gate as fixed. */
1875
+ partial?: boolean;
1876
+ /** Part of the fix has to be done by hand (unpatched trackers, unsupported consent platform, entangled code). */
1877
+ manual?: boolean;
1878
+ /** Reported trackers that are not covered by a patch (state "unpatched" | "manual"). */
1879
+ unpatched?: TrackerStatus[];
1880
+ /** Status of every reported tracker name. */
1881
+ trackerStatus?: TrackerStatus[];
1882
+ /** Supported consent platforms (OneTrust, Cookiebot) found in the source: their category consent is read automatically, no hook needed. */
1883
+ cmpSupported?: string[];
1884
+ /** How a custom consent banner talks to the injected runtime (code lines, ready to paste). */
1885
+ integrationHooks?: string[];
1886
+ /** Plain-text instructions for PR body and console: what to fix by hand, and the consent hooks. */
1887
+ manualSteps?: string;
1888
+ /** Hint when a requested commit/PR could not be made (e.g. the source dir is in no git repository); the fix stays local. */
1889
+ gitNote?: string;
1890
+ }
1389
1891
  interface RemediationEngineInterface {
1390
- remediate(report: LeakReport, config: GateConfig): Promise<RemediationResult>;
1892
+ remediate(report: LeakReport, config: GateConfig): Promise<RemediationOutcome>;
1391
1893
  }
1392
1894
 
1393
1895
  interface CodeReviewerInterface {
1394
1896
  review(patches: FilePatch[], report: LeakReport, config: GateConfig): Promise<ReviewVerdict>;
1395
1897
  }
1396
1898
 
1899
+ /** What the fix does NOT cover and how a custom consent banner talks to the injected runtime. */
1900
+ interface PullRequestExtras {
1901
+ unpatched?: TrackerStatus[];
1902
+ integrationHooks?: string[];
1903
+ /** Set when a supported CMP (OneTrust, Cookiebot) was recognised: it is read automatically, no hook is needed. */
1904
+ consentNote?: string;
1905
+ }
1397
1906
  declare class PullRequestEngine {
1398
1907
  private git;
1399
1908
  /**
1400
1909
  * Creates a fix branch, commits only the given files, pushes and opens a PR when a remote + token exist.
1401
1910
  * Always returns to the starting branch. Throws on any git/API failure (caller restores the working tree).
1402
1911
  */
1403
- createPullRequest(patches: FilePatch[], report: LeakReport, reviewVerdict: ReviewVerdict, config: GateConfig): Promise<PullRequestResult>;
1912
+ createPullRequest(patches: FilePatch[], report: LeakReport, reviewVerdict: ReviewVerdict, config: GateConfig, extras?: PullRequestExtras): Promise<PullRequestResult>;
1404
1913
  private resolveBaseBranch;
1405
- buildPrDescription(report: LeakReport, reviewVerdict: ReviewVerdict, patches: FilePatch[], config: GateConfig): string;
1914
+ buildPrDescription(report: LeakReport, reviewVerdict: ReviewVerdict, patches: FilePatch[], config: GateConfig, extras?: PullRequestExtras): string;
1406
1915
  }
1407
1916
 
1408
- /**
1409
- * Injected when trackers are deferred. Activates `script[type=text/plain][data-src]`
1410
- * and runs registered inits once consent is granted — including late accept clicks.
1411
- */
1412
- declare 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=\u2026)\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>";
1413
1917
  declare class RemediationEngine implements RemediationEngineInterface {
1414
1918
  private reviewer;
1415
1919
  private prEngine;
1416
1920
  constructor(reviewer?: CodeReviewerInterface, prEngine?: PullRequestEngine);
1417
- remediate(report: LeakReport, config: GateConfig): Promise<RemediationResult>;
1921
+ remediate(report: LeakReport, config: GateConfig): Promise<RemediationOutcome>;
1418
1922
  private findCandidateSourceFiles;
1419
1923
  /**
1420
- * Deterministic Privacy Patcher: Analyzes violations and injects consent gates or CMP categorization attributes
1924
+ * Deterministic Privacy Patcher: defers tracker execution until category consent.
1925
+ * HTML is patched script block by script block (everything else stays byte-identical); SPA sources get
1926
+ * consent guards. Anything that cannot be patched safely is returned as a manual instruction instead.
1421
1927
  */
1422
1928
  private remediateWithRuleEngine;
1423
1929
  /**
1424
- * LLM API Remediation: Queries OpenAI/Anthropic/Gemini to generate surgical code patches
1930
+ * LLM API Remediation (OpenAI only, explicit opt-in checked by the caller): generates surgical code patches
1931
+ * for the files that actually reference the leaking tracker. Page-controlled strings are delimited as untrusted.
1425
1932
  */
1426
1933
  private remediateWithLlm;
1427
1934
  /**
@@ -1431,12 +1938,61 @@ declare class RemediationEngine implements RemediationEngineInterface {
1431
1938
  private sanitizeLlmPatches;
1432
1939
  }
1433
1940
 
1941
+ /**
1942
+ * Kernszenarien: Ablehnen- und Akzeptieren-Pfad bedienen den Banner.
1943
+ * Sind sie nicht prüfbar, sagt der Scan über Consent nichts aus — das Gate darf dann nicht PASS melden.
1944
+ */
1945
+ declare const CORE_SCENARIOS: readonly ChaosScenario[];
1946
+ /** Gruppiert Befunde zu Befundgruppen (Regel + Tracker). */
1947
+ declare function groupFindings(violations: {
1948
+ ruleId?: string;
1949
+ trackerName: string;
1950
+ }[]): {
1951
+ key: string;
1952
+ ruleId: string;
1953
+ trackerName: string;
1954
+ count: number;
1955
+ }[];
1956
+ /** Bewertet die Vollständigkeit des Scans. */
1957
+ declare function assessReport(report: LeakReport, scenarios?: ChaosScenario[], options?: {
1958
+ strict?: boolean;
1959
+ }): GateAssessment;
1960
+
1961
+ /** Prüft, ob die Zielseite antwortet und nicht mit 4xx/5xx; wirft sonst einen neutralen Fehler. */
1962
+ declare function checkTargetReachable(url: string, timeoutMs: number, fetchImpl?: typeof fetch): Promise<number>;
1963
+ type Preflight = (config: GateConfig) => Promise<unknown>;
1964
+ /** Lizenzpflichtige Funktionen, die in diesem Lauf angefordert wurden (Bezeichnung für Konsole/Summary). */
1965
+ declare function requestedLicensedFeatures(config: GateConfig): string[];
1966
+ /** Hinweistext, warum lizenzpflichtige Funktionen nicht liefen; nennt die konkret übersprungene Funktion. */
1967
+ declare function licenseSkipText(config: GateConfig, skipped: string[]): string;
1968
+ /**
1969
+ * Gründe, warum Szenarien nicht prüfbar sind, aus deren Notiz («Nicht prüfbar: <Grund> (zuvor: …)» bzw.
1970
+ * «Szenario nicht prüfbar — <Grund> (kein grünes Häkchen)»); identische Gründe stehen einmal mit allen Szenarien.
1971
+ */
1972
+ declare function uncheckableReasons(report: LeakReport, scenarios: ChaosScenario[]): {
1973
+ reason: string;
1974
+ scenarios: ChaosScenario[];
1975
+ }[];
1434
1976
  declare class PrivacyChaosGate {
1435
- private scanner;
1977
+ private scanner?;
1436
1978
  private remediationEngine;
1437
- constructor(scanner?: ChaosScannerInterface, remediationEngine?: RemediationEngineInterface);
1438
- run(config: GateConfig): Promise<GateExecutionResult>;
1979
+ private preflight?;
1980
+ /**
1981
+ * @param preflight Erreichbarkeits-Check vor dem Scan. Default: HTTP-Check (nur mit dem Standard-Scanner);
1982
+ * wer einen eigenen Scanner injiziert, ist selbst für die Zielseite zuständig.
1983
+ */
1984
+ constructor(scanner?: ChaosScannerInterface, remediationEngine?: RemediationEngineInterface, preflight?: Preflight);
1985
+ run(input: GateConfigInput): Promise<GateExecutionResult>;
1986
+ private printExitNotes;
1987
+ /** Aussage zum Re-Scan, ohne mehr zu behaupten als gemessen wurde. */
1988
+ private rescanNote;
1989
+ private proposalOf;
1990
+ /** Hinweise zu einem lokal angelegten Fix-Branch (kein Token/Remote): wo der Fix liegt, ob der Arbeitsbaum geändert ist. */
1991
+ private localBranchNotes;
1992
+ private proposalText;
1439
1993
  private saveReport;
1994
+ /** Komprimierte Fassungen (data-URI) für die Screenshots, sobald deren Gesamtgrösse einbettungsrelevant ist. */
1995
+ private embeddableScreenshots;
1440
1996
  private writeGitHubOutputs;
1441
1997
  private writeGitHubSummary;
1442
1998
  }
@@ -1448,9 +2004,16 @@ declare class PrivacyChaosGate {
1448
2004
  */
1449
2005
  interface EvidenceMarkdownOptions {
1450
2006
  demo?: boolean;
2007
+ /** Gate-Zustand aus dem Orchestrator; ohne Angabe wird er nur aus den Befunden abgeleitet. */
2008
+ gate?: ReportGate;
2009
+ /** Kundenname (Kundenreport) */
2010
+ client?: string;
1451
2011
  }
2012
+
1452
2013
  /** Status-Lesart für beide Renderer — eine Quelle, kein Drift. */
1453
2014
  declare function statusLabelOf(s: EvidenceRecord["status"]): string;
2015
+ /** Status eines Szenarios samt Zusatz: «bestanden (Befunde ignoriert)», wenn alle seine Befunde per --ignore ausgenommen wurden. */
2016
+ declare function evidenceLabelOf(e: EvidenceRecord): string;
1454
2017
  /** Zählung und Gate-Text — von Markdown und HTML gemeinsam genutzt. */
1455
2018
  interface ReportFacts {
1456
2019
  evidenceCount: number;
@@ -1459,9 +2022,22 @@ interface ReportFacts {
1459
2022
  uncheckable: number;
1460
2023
  notApplicable: number;
1461
2024
  incomplete: number;
2025
+ /** Gate-blockierende Befunde (Request-Zeilen); Hinweise stehen in `advisory` */
1462
2026
  findings: number;
2027
+ advisory: number;
2028
+ ignored: number;
1463
2029
  observedCount: number;
1464
- gate: "PASS" | "BLOCKED";
2030
+ /** Kurzlabel: PASS | BLOCKED | UNVOLLSTÄNDIG */
2031
+ gate: "PASS" | "BLOCKED" | "UNVOLLSTÄNDIG";
2032
+ gateState: GateState;
2033
+ /** Volltext hinter «Technisches Gate: » (z. B. «UNVOLLSTÄNDIG — 2 von 15 Szenarien nicht prüfbar») */
2034
+ gateHeadline: string;
2035
+ /** Ton der Gate-Karte: ok | blocked | warn */
2036
+ gateTone: "ok" | "blocked" | "warn";
2037
+ /** Geprüft = bestanden + auffällig; nicht prüfbar laut Orchestrator (sonst aus den Nachweisen) */
2038
+ checked: number;
2039
+ uncheckableTotal: number;
2040
+ scenariosTotal?: number;
1465
2041
  findingsText: string;
1466
2042
  gateDisclaimer: string;
1467
2043
  problemCount: number;
@@ -1475,28 +2051,34 @@ interface CodeSolution {
1475
2051
  code: string;
1476
2052
  }
1477
2053
  /** Nur Regeln mit belegtem Befund bekommen eine Code-Lösung. */
1478
- declare function codeSolutionsFor(report: LeakReport): CodeSolution[];
1479
- declare function deriveReportFacts(report: LeakReport): ReportFacts;
2054
+ declare function codeSolutionsFor(report: LeakReport, strict?: boolean): CodeSolution[];
2055
+ declare function deriveReportFacts(report: LeakReport, gate?: ReportGate): ReportFacts;
2056
+ /** Gate-Zustand für Deckblatt/PDF: dieselbe Ableitung wie im Report. */
2057
+ declare function resolveReportGate(report: LeakReport, gate?: ReportGate): ReportFacts;
2058
+ /**
2059
+ * Zusatzhinweise zum Gate-Zustand (Banner nicht erkannt, Teilfix, Scanner-Warnungen, breites Ignore-Muster).
2060
+ * Eine Quelle für Markdown, HTML und Deckblatt.
2061
+ */
2062
+ declare function gateNotesOf(gate: ReportGate | undefined): {
2063
+ state: string;
2064
+ warnings: string[];
2065
+ };
1480
2066
  /** 1 Befund-Zeile / N Befund-Zeilen — nie «Befund-Zeile(n)». */
1481
2067
  declare function findingsCountText(n: number): string;
1482
2068
  /** Kundennutzen: Befundgruppen statt Request-Zeilen. */
1483
2069
  declare function problemsTextOf(n: number): string;
1484
- /** Gruppiert Befunde zu Befundgruppen (Regel + Tracker). */
1485
- declare function groupFindings(violations: {
1486
- ruleId?: string;
1487
- trackerName: string;
1488
- }[]): {
1489
- key: string;
1490
- ruleId: string;
1491
- trackerName: string;
1492
- count: number;
1493
- }[];
1494
2070
  /** Zähltext: Requests, nicht vage «×». */
1495
2071
  declare function reproductionText(count: number): string;
1496
2072
  declare function buildEvidenceMarkdown(report: LeakReport, title?: string, options?: EvidenceMarkdownOptions): string;
1497
2073
  interface EvidenceHtmlOptions {
1498
2074
  /** Demo-Lauf mit synthetischen Testdaten klar kennzeichnen */
1499
2075
  demo?: boolean;
2076
+ /** Gate-Zustand aus dem Orchestrator; ohne Angabe wird er nur aus den Befunden abgeleitet. */
2077
+ gate?: ReportGate;
2078
+ /** Kundenname (Kundenreport) */
2079
+ client?: string;
2080
+ /** Komprimierte Fassungen der Screenshots (Originalpfad → data-URI), siehe `compressScreenshots` */
2081
+ shotSources?: ReadonlyMap<string, string>;
1500
2082
  }
1501
2083
  /**
1502
2084
  * HTML-Beweisreport im offiziellen CuonzTech-Brand (Terminal-Schwarz, Gold,
@@ -1523,6 +2105,8 @@ interface CoverOptions {
1523
2105
  issuedAt?: string;
1524
2106
  /** Demo-Lauf mit synthetischen Testdaten — muss aufs Deckblatt */
1525
2107
  demo?: boolean;
2108
+ /** Gate-Zustand aus dem Orchestrator; ohne Angabe wird er nur aus den Befunden abgeleitet. */
2109
+ gate?: ReportGate;
1526
2110
  }
1527
2111
  declare function buildCoverHtml(report: LeakReport, options?: CoverOptions): string;
1528
2112
  /**
@@ -1538,8 +2122,46 @@ declare function renderDeluxeCombined(coverHtml: string, evidenceHtmlPath: strin
1538
2122
  declare function renderDeluxePdf(coverHtml: string, evidenceHtmlPath: string, outPath: string): Promise<string>;
1539
2123
 
1540
2124
  /**
1541
- * Programmatic convenience function to run CPCG
2125
+ * Lizenzstatus für die lizenzpflichtigen Funktionen (PDF-Report, Kundenreport, Fix-Commit/PR).
2126
+ * Scan und Konsolen-Gate sind lizenzfrei — nur `invalid` beendet den Lauf (Exit 2).
2127
+ * `unreachable` (Kunden-Key, Lizenzserver weg, kein Grant im Cache) ist ausdrücklich KEIN Fehler:
2128
+ * ein frischer CI-Runner ohne Netz zum Lizenzserver darf das Gate nicht kippen.
2129
+ */
2130
+ type Entitlement = {
2131
+ status: "licensed";
2132
+ kind: "pilot" | "customer-key";
2133
+ summary: string;
2134
+ } | {
2135
+ status: "none";
2136
+ } | {
2137
+ status: "unreachable";
2138
+ detail: string;
2139
+ } | {
2140
+ status: "invalid";
2141
+ messages: string[];
2142
+ };
2143
+ interface EntitlementInput {
2144
+ /** Wert von `--license` (Vorrang vor Env CPCG_LICENSE) */
2145
+ license?: string;
2146
+ /** Default: process.env */
2147
+ env?: NodeJS.ProcessEnv;
2148
+ /** Test-Stubs */
2149
+ fetchImpl?: typeof fetch;
2150
+ publicKey?: string;
2151
+ }
2152
+ declare const LICENSE_CONTACT = "support@cuonztech.ch bzw. cuonztech.ch/privacy-chaos-gate";
2153
+ declare function resolveEntitlement(input?: EntitlementInput): Promise<Entitlement>;
2154
+
2155
+ /**
2156
+ * Loopback-Ziele (Entwicklung, Fixture-Tests) sind lizenzfrei. Nur der Hostname entscheidet,
2157
+ * nie ein Substring der URL (`https://evil.example/?localhost`, `localhost.evil.example`).
2158
+ */
2159
+ declare function isLoopbackTarget(url: string): boolean;
2160
+
2161
+ /**
2162
+ * Programmatic convenience function to run CPCG.
2163
+ * Akzeptiert CLI-artige Optionen oder eine (teilweise) Konfiguration; Defaults werden ergänzt.
1542
2164
  */
1543
- declare function runGate(optionsOrConfig: CliRawOptions | GateConfig): Promise<GateExecutionResult>;
2165
+ declare function runGate(optionsOrConfig: CliRawOptions | GateConfigInput): Promise<GateExecutionResult>;
1544
2166
 
1545
- export { CONSENT_ACTIVATION_RUNTIME, ChaosScanner, type ChaosScannerInterface, type ChaosScenario, ChaosScenarioSchema, type CliRawOptions, type CodeSolution, type CoverOptions, type EvidenceHtmlOptions, type EvidenceMarkdownOptions, type EvidenceRecord, EvidenceRecordSchema, type EvidenceStatus, EvidenceStatusSchema, type FilePatch, FilePatchSchema, type GateConfig, GateConfigSchema, type GateExecutionResult, type LeakReport, LeakReportSchema, PrivacyChaosGate, type PullRequestResult, PullRequestResultSchema, RemediationEngine, type RemediationEngineInterface, type RemediationResult, RemediationResultSchema, type ReportFacts, type RequestEvent, RequestEventSchema, type ReviewVerdict, ReviewVerdictSchema, type StorageSnapshot, StorageSnapshotSchema, type TrackerCategory, TrackerCategorySchema, type TrackerViolation, TrackerViolationSchema, buildCoverHtml, buildEvidenceHtml, buildEvidenceMarkdown, clickFirstSameOriginLink, codeSolutionsFor, deriveReportFacts, findingsCountText, groupFindings, isOnTargetOrigin, problemsTextOf, renderDeluxeCombined, renderDeluxePdf, reproductionText, resolveGateConfig, runGate, statusLabelOf };
2167
+ export { type BannerIssue, CORE_SCENARIOS, ChaosScanner, type ChaosScannerInterface, type ChaosScenario, ChaosScenarioSchema, type CliRawOptions, type CodeSolution, type CoverOptions, ENV_FILE_KEYS_HELP, EXIT, type Entitlement, type EntitlementInput, type EvidenceHtmlOptions, type EvidenceMarkdownOptions, type EvidenceRecord, EvidenceRecordSchema, type EvidenceStatus, EvidenceStatusSchema, type FilePatch, FilePatchSchema, type GateAssessment, type GateConfig, type GateConfigInput, GateConfigSchema, type GateExecutionResult, type GateState, type IgnoredFinding, JurisdictionCodeSchema, LICENSE_CONTACT, type LeakReport, LeakReportSchema, PrivacyChaosGate, type PullRequestResult, PullRequestResultSchema, RemediationEngine, type RemediationEngineInterface, type RemediationResult, RemediationResultSchema, type ReportFacts, type ReportGate, type RequestEvent, RequestEventSchema, type ReviewVerdict, ReviewVerdictSchema, type SamplingInfo, type StorageSnapshot, StorageSnapshotSchema, type TrackerCategory, TrackerCategorySchema, type TrackerViolation, TrackerViolationSchema, assessReport, buildCoverHtml, buildEvidenceHtml, buildEvidenceMarkdown, checkTargetReachable, codeSolutionsFor, deriveReportFacts, evidenceLabelOf, findingsCountText, gateNotesOf, groupFindings, isEnvKeyAllowedFromFile, isLoopbackTarget, licenseSkipText, loadProjectEnv, parseGateConfig, problemsTextOf, renderDeluxeCombined, renderDeluxePdf, reproductionText, requestedLicensedFeatures, resolveEntitlement, resolveGateConfig, resolveReportGate, runGate, statusLabelOf, uncheckableReasons };