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.js CHANGED
@@ -1,11 +1,15 @@
1
1
  import {
2
- CONSENT_ACTIVATION_RUNTIME,
2
+ CORE_SCENARIOS,
3
3
  ChaosScanner,
4
4
  ChaosScenarioSchema,
5
+ ENV_FILE_KEYS_HELP,
6
+ EXIT,
5
7
  EvidenceRecordSchema,
6
8
  EvidenceStatusSchema,
7
9
  FilePatchSchema,
8
10
  GateConfigSchema,
11
+ JurisdictionCodeSchema,
12
+ LICENSE_CONTACT,
9
13
  LeakReportSchema,
10
14
  PrivacyChaosGate,
11
15
  PullRequestResultSchema,
@@ -16,37 +20,52 @@ import {
16
20
  StorageSnapshotSchema,
17
21
  TrackerCategorySchema,
18
22
  TrackerViolationSchema,
23
+ assessReport,
19
24
  buildCoverHtml,
20
25
  buildEvidenceHtml,
21
26
  buildEvidenceMarkdown,
22
- clickFirstSameOriginLink,
27
+ checkTargetReachable,
23
28
  codeSolutionsFor,
24
29
  deriveReportFacts,
30
+ evidenceLabelOf,
25
31
  findingsCountText,
32
+ gateNotesOf,
26
33
  groupFindings,
27
- isOnTargetOrigin,
34
+ isEnvKeyAllowedFromFile,
35
+ isLoopbackTarget,
36
+ licenseSkipText,
37
+ loadProjectEnv,
38
+ parseGateConfig,
28
39
  problemsTextOf,
29
40
  renderDeluxeCombined,
30
41
  renderDeluxePdf,
31
42
  reproductionText,
43
+ requestedLicensedFeatures,
44
+ resolveEntitlement,
32
45
  resolveGateConfig,
33
- statusLabelOf
34
- } from "./chunk-T5D6BUAC.js";
46
+ resolveReportGate,
47
+ statusLabelOf,
48
+ uncheckableReasons
49
+ } from "./chunk-42D7PLVP.js";
35
50
 
36
51
  // src/index.ts
37
52
  async function runGate(optionsOrConfig) {
38
- const config = "targetUrl" in optionsOrConfig && typeof optionsOrConfig.targetUrl === "string" ? optionsOrConfig : resolveGateConfig(optionsOrConfig);
53
+ const input = "targetUrl" in optionsOrConfig && typeof optionsOrConfig.targetUrl === "string" ? optionsOrConfig : resolveGateConfig(optionsOrConfig);
39
54
  const gate = new PrivacyChaosGate();
40
- return gate.run(config);
55
+ return gate.run(input);
41
56
  }
42
57
  export {
43
- CONSENT_ACTIVATION_RUNTIME,
58
+ CORE_SCENARIOS,
44
59
  ChaosScanner,
45
60
  ChaosScenarioSchema,
61
+ ENV_FILE_KEYS_HELP,
62
+ EXIT,
46
63
  EvidenceRecordSchema,
47
64
  EvidenceStatusSchema,
48
65
  FilePatchSchema,
49
66
  GateConfigSchema,
67
+ JurisdictionCodeSchema,
68
+ LICENSE_CONTACT,
50
69
  LeakReportSchema,
51
70
  PrivacyChaosGate,
52
71
  PullRequestResultSchema,
@@ -57,21 +76,31 @@ export {
57
76
  StorageSnapshotSchema,
58
77
  TrackerCategorySchema,
59
78
  TrackerViolationSchema,
79
+ assessReport,
60
80
  buildCoverHtml,
61
81
  buildEvidenceHtml,
62
82
  buildEvidenceMarkdown,
63
- clickFirstSameOriginLink,
83
+ checkTargetReachable,
64
84
  codeSolutionsFor,
65
85
  deriveReportFacts,
86
+ evidenceLabelOf,
66
87
  findingsCountText,
88
+ gateNotesOf,
67
89
  groupFindings,
68
- isOnTargetOrigin,
90
+ isEnvKeyAllowedFromFile,
91
+ isLoopbackTarget,
92
+ licenseSkipText,
93
+ loadProjectEnv,
94
+ parseGateConfig,
69
95
  problemsTextOf,
70
96
  renderDeluxeCombined,
71
97
  renderDeluxePdf,
72
98
  reproductionText,
99
+ requestedLicensedFeatures,
100
+ resolveEntitlement,
73
101
  resolveGateConfig,
102
+ resolveReportGate,
74
103
  runGate,
75
- statusLabelOf
104
+ statusLabelOf,
105
+ uncheckableReasons
76
106
  };
77
- //# sourceMappingURL=index.js.map
@@ -1,13 +1,17 @@
1
1
  # Cuonztech Privacy Chaos Gate
2
- ## Evidence Report ”” Consent-Pre-Consent-Leaks auf pilot-kunde.ch
2
+ ## Evidence Report — Consent-Pre-Consent-Leaks auf pilot-kunde.ch
3
+
4
+ > **BEISPIELBERICHT (Demo):** Dieses Dokument zeigt das Format eines Evidence-Reports an einem
5
+ > **erfundenen Beispiel**. `pilot-kunde.ch`, die Tag-ID `GTM-DEMO01`, das Datum und alle Zahlen sind
6
+ > Platzhalter aus Demo-Daten. Es beschreibt keinen realen Kunden und keine reale Website.
3
7
 
4
8
  **Produkt:** Cuonztech Privacy Chaos Gate (CPCG)
5
9
  **Kategorie:** CI-Gate · Chaos-Scanner · Auto-Fix-PR
6
- **Auftraggeber/Pilot:** Read-only Audit, 20.10.2026
7
- **Status:** Gate BLOCKED ”” 10 Tracker-Leaks vor Einwilligung
10
+ **Auftraggeber/Pilot:** Beispiel (Platzhalter), Read-only Audit, 20.10.2026
11
+ **Status:** Gate BLOCKED — 10 Tracker-Leaks vor Einwilligung (Beispielwerte)
8
12
 
9
- > âš ï¸ **Hinweis / Disclaimer:** CPCG ist ein technisches Hilfsmittel zur Unterstützung bei der
10
- > Implementierung von Consent-Lösungen ”” **keine Rechtsberatung** und keine Garantie für
13
+ > ⚠️ **Hinweis / Disclaimer:** CPCG ist ein technisches Hilfsmittel zur Unterstützung bei der
14
+ > Implementierung von Consent-Lösungen — **keine Rechtsberatung** und keine Garantie für
11
15
  > DSGVO-/TTDSG-Konformität. Bitte lassen Sie die endgültige Umsetzung anwaltlich prüfen.
12
16
  > / CPCG is a technical aid, **not legal advice** and no guarantee of GDPR/ePrivacy compliance.
13
17
 
@@ -16,8 +20,8 @@
16
20
  ## 1. Was ist passiert?
17
21
 
18
22
  Die Produktionsseite **pilot-kunde.ch** setzt professionell auf **OneTrust** (`cdn.cookielaw.org`,
19
- Domain-Script `151e70dd-”¦`). Trotzdem lädt der **Google-Tag-Manager-Bootstrap**
20
- (`GTM-DEMO01`) **ungedeckt im HTML-Head** ”” **bevor** das OneTrust-Banner irgendeine
23
+ Domain-Script `151e70dd-…`). Trotzdem lädt der **Google-Tag-Manager-Bootstrap**
24
+ (`GTM-DEMO01`) **ungedeckt im HTML-Head** — **bevor** das OneTrust-Banner irgendeine
21
25
  Entgegennahme von Einwilligung darstellt.
22
26
 
23
27
  Ergebnis des CPCG-Chaos-Scans: **10 Unauthorized Tracker Requests**.
@@ -47,76 +51,64 @@ Ergebnis des CPCG-Chaos-Scans: **10 Unauthorized Tracker Requests**.
47
51
 
48
52
  ```html
49
53
  <!-- OneTrust Cookies Consent Notice start for pilot-kunde.ch -->
50
- <script src="https://cdn.cookielaw.org/consent/151e70dd-”¦/OtAutoBlock.js"></script>
51
- <script src="https://cdn.cookielaw.org/scripttemplates/otSDKStub.js" ”¦></script>
54
+ <script src="https://cdn.cookielaw.org/consent/151e70dd-…/OtAutoBlock.js"></script>
55
+ <script src="https://cdn.cookielaw.org/scripttemplates/otSDKStub.js" …></script>
52
56
 
53
- <!-- Google Tag Manager ”” läuft ohne Consent -->
54
- <script>(function(w,d,s,l,i){ ”¦ j.src='https://www.googletagmanager.com/gtm.js?id='+i;
57
+ <!-- Google Tag Manager — läuft ohne Consent -->
58
+ <script>(function(w,d,s,l,i){ … j.src='https://www.googletagmanager.com/gtm.js?id='+i;
55
59
  })(window,document,'script','dataLayer','GTM-DEMO01');</script>
56
60
  ```
57
61
 
58
62
  ---
59
63
 
60
- ## 3. Warum das ein echtes Produkt-Feature ist
64
+ ## 3. Einordnung
61
65
 
62
- | Wettbewerber | Können Sie | Können Sie **nicht** |
63
- |--------------|------------|----------------------|
64
- | Cookiebot / Usercentrics / Ketch / Osano | CMP, Banner, Consent-Storage | **CI-Gate + Auto-Fix-PR** |
65
- | CookieYes / Webxray | Cookie-Scan, Reporting | **Chaos-Szenarien (Fast-Click, Network-Drop) + Fix-PR** |
66
- | **Cuonztech CPCG** | Pre-Consent-Detektion + Auto-Fix-PR im CI | ”” |
66
+ CMPs prüfen vorrangig die **Konfiguration** (Banner, Kategorien, Consent-Speicherung), CPCG prüft das **Verhalten**
67
+ der laufenden Seite im Browser. CPCG ersetzt kein CMP und keine Rechtsberatung, sondern ergänzt beides.
67
68
 
68
- **Differenzierung:** Shift-Left. Nicht nach dem Go-Live dokumentieren, sondern vor dem
69
- Merge blockieren ”” und den Fix als Pull Request liefern.
69
+ | | Schwerpunkt | Zeitpunkt |
70
+ |---|---|---|
71
+ | CMP (typisch) | Konfiguration: Banner, Kategorien, Consent-Speicherung | im Betrieb der Seite |
72
+ | **CuonzTech CPCG** | Verhalten: welche Requests laufen vor und nach der Einwilligung (Fast-Click, Network-Drop u. a.) | im CI vor dem Merge oder als Stichprobe; optional mit Fix-Vorschlag |
70
73
 
71
- ---
74
+ **Ansatz:** Shift-Left. Nicht erst nach dem Go-Live dokumentieren, sondern vor dem Merge prüfen.
72
75
 
73
- ## 4. Empfohlener Fix (Auszug ”” nicht ohne Kunden-Freigabe anwenden)
76
+ ---
74
77
 
75
- **Vorher (verkürzt):**
76
- ```html
77
- <script>(function(w,d,s,l,i){ ”¦ j.src='https://www.googletagmanager.com/gtm.js?id='+i; ”¦
78
- })(window,document,'script','dataLayer','GTM-DEMO01');</script>
79
- ```
78
+ ## 4. Fix-Prinzip (nicht ohne Kunden-Freigabe anwenden)
80
79
 
81
- **Nachher (Prinzip ”” Consent Mode v2 default denied):**
82
- ```html
83
- <script type="text/plain" data-cookiecategory="analytics"
84
- data-src="https://www.googletagmanager.com/gtm.js?id=GTM-DEMO01"></script>
85
- <script data-cpcg="deferred-gtm">
86
- window.dataLayer = window.dataLayer || [];
87
- function gtag(){dataLayer.push(arguments);}
88
- gtag('consent','default',{ad_storage:'denied',analytics_storage:'denied',wait_for_update:500});
89
- window.__cpcgInits = window.__cpcgInits || [];
90
- window.__cpcgInits.push(function(){
91
- if (localStorage.getItem('OptanonConsent') !== 'accepted') return;
92
- gtag('consent','update',{ad_storage:'granted',analytics_storage:'granted'});
93
- // GTM-Bootstrap erst hier laden ”¦
94
- });
95
- </script>
96
- ```
80
+ Das Tracker-Skript darf erst nach der Einwilligung der passenden Kategorie (Statistik/Marketing)
81
+ laden, nicht im Head ohne Consent-Prüfung. Den konkreten Patch erzeugt CPCG im Scan-Lauf mit
82
+ `--auto-fix` und `--source-dir <Quellverzeichnis>`; er steht als Diff im Report. Bei OneTrust und
83
+ Cookiebot liest der Patch die Kategorien automatisch, bei eigenen Bannern meldet die Seite die
84
+ Einwilligung an die eingefügte Runtime. Andere Consent-Plattformen und Tracker, die nicht im
85
+ Quelltext stehen (Tag Manager, Server, CMS), bleiben «manuell zu beheben» (siehe README, Abschnitt
86
+ «Auto-Fix: Grenzen»). Dieses Beispiel enthält bewusst keinen Beispiel-Patch: ein gekürzter Code
87
+ würde nicht dem echten Ausgabeformat entsprechen.
97
88
 
98
- **Nach Umsetzung:** Rescan über CPCG muss `GATE RESULT: PASS` liefern.
89
+ **Nach Umsetzung:** Ein erneuter Scan muss ein grünes Gate liefern (Exit-Code 0).
99
90
 
100
91
  ---
101
92
 
102
93
  ## 5. Was der Kunde bekommt (Produkt-Fluss)
103
94
 
104
95
  1. **Online-Kauf** auf cuonztech.ch → Lizenzcode per E-Mail
105
- 2. **Scan:** `npx @cuonztech/privacy-chaos-gate --url <staging> --license <code>`
106
- 3. **Report** (JSON + Markdown, dieses Template)
107
- 4. **Auto-Fix-PR** (optional, mit Review-Agent)
108
- 5. **CI-Gate** im GitHub-Action-Workflow ”” Merge-Blocker bei Pre-Consent-Leaks
96
+ 2. **Scan:** `npx cuonztech-privacy-chaos-gate --url <staging>`. Scan und Konsolen-Gate brauchen keine Lizenz.
97
+ 3. **Report** (JSON + Markdown/HTML). Den **Kundenreport** (mit `--client`, PDF mit `--report-pdf`) schaltet die Lizenz frei:
98
+ Code per Umgebungsvariable `CPCG_LICENSE` übergeben.
99
+ 4. **Auto-Fix-PR** (optional, mit Review-Agent; Commit/PR brauchen eine Lizenz, das lokale Anwenden nicht)
100
+ 5. **CI-Gate** im GitHub-Action-Workflow — Merge-Blocker bei Pre-Consent-Leaks
109
101
 
110
102
  ---
111
103
 
112
104
  ## 6. Nächste Schritte
113
105
 
114
106
  - [ ] Technische Umsetzung Fix (intern oder CPCG Auto-Fix-PR)
115
- - [ ] Juristische Prüfung (Datenschutzbeauftragte/r) ”” siehe Disclaimer
107
+ - [ ] Juristische Prüfung (Datenschutzbeauftragte/r) — siehe Disclaimer
116
108
  - [ ] Rescan + Freigabe
117
109
  - [ ] CPCG als CI-Gate in die Pipeline
118
110
 
119
111
  ---
120
112
 
121
- *© Cuonztech ”” Cuonztech Privacy Chaos Gate (CPCG)*
113
+ *© Cuonztech — Cuonztech Privacy Chaos Gate (CPCG)*
122
114
  *Technisches Hilfsmittel, keine Rechtsberatung.*
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cuonztech-privacy-chaos-gate",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "CuonzTech Privacy Chaos Gate — CI/CD Consent-Scanner, Chaos-Szenarien und Auto-Fix-PR",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -10,11 +10,11 @@
10
10
  "type": "module",
11
11
  "files": [
12
12
  "dist",
13
+ "!dist/**/*.map",
13
14
  "action.yml",
15
+ "LICENSE",
14
16
  "README.md",
15
- "docs/BRAND-PILOT-EVIDENCE.md",
16
- "docs/LIZENZ-KAUFFLUSS.md",
17
- "docs/PREISMODELL.md"
17
+ "docs/BRAND-PILOT-EVIDENCE.md"
18
18
  ],
19
19
  "engines": {
20
20
  "node": ">=20"
@@ -36,6 +36,7 @@
36
36
  "test": "vitest run",
37
37
  "test:watch": "vitest",
38
38
  "typecheck": "tsc --noEmit",
39
+ "typecheck:all": "tsc -p tsconfig.test.json --noEmit",
39
40
  "prepublishOnly": "pnpm run typecheck && pnpm run test && pnpm run build",
40
41
  "demo": "tsx scripts/scan-demo-portal.mts && tsx scripts/make-deluxe-report.mts && tsx scripts/package-delivery.mts",
41
42
  "demo:report": "tsx scripts/make-deluxe-report.mts"
@@ -52,7 +53,7 @@
52
53
  "cuonztech"
53
54
  ],
54
55
  "author": "CuonzTech · Carlo Cuonz",
55
- "license": "MIT",
56
+ "license": "SEE LICENSE IN LICENSE",
56
57
  "dependencies": {
57
58
  "commander": "^12.1.0",
58
59
  "dotenv": "^16.4.5",
@@ -1,36 +0,0 @@
1
- // src/core/license/ed25519.ts
2
- import crypto from "crypto";
3
-
4
- // src/core/license/publicKey.ts
5
- var LICENSE_PUBLIC_KEY = "q20XyLRZGURVvMLR6q0SCIc6poLhW73KE5Ds94Yq1FQ=";
6
-
7
- // src/core/license/ed25519.ts
8
- var PKCS8_PREFIX = Buffer.from("302e020100300506032b657004220420", "hex");
9
- var SPKI_PREFIX = Buffer.from("302a300506032b6570032100", "hex");
10
- function rawKey(b64, what) {
11
- const raw = Buffer.from(b64, "base64");
12
- if (raw.length !== 32) throw new Error(`${what}: erwartet 32 Byte (base64), erhalten ${raw.length}`);
13
- return raw;
14
- }
15
- function defaultPublicKey() {
16
- return process.env.CPCG_LICENSE_PUBLIC_KEY || LICENSE_PUBLIC_KEY;
17
- }
18
- function verifyEd25519(domain, payload, sigB64url, publicKeyB64 = defaultPublicKey()) {
19
- try {
20
- const key = crypto.createPublicKey({
21
- key: Buffer.concat([SPKI_PREFIX, rawKey(publicKeyB64, "Public Key")]),
22
- format: "der",
23
- type: "spki"
24
- });
25
- const sig = Buffer.from(sigB64url, "base64url");
26
- return sig.length === 64 && crypto.verify(null, Buffer.from(`${domain}.${payload}`), key, sig);
27
- } catch {
28
- return false;
29
- }
30
- }
31
-
32
- export {
33
- defaultPublicKey,
34
- verifyEd25519
35
- };
36
- //# sourceMappingURL=chunk-FN3QUFUZ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/license/ed25519.ts","../src/core/license/publicKey.ts"],"sourcesContent":["import crypto from \"node:crypto\";\nimport { LICENSE_PUBLIC_KEY } from \"./publicKey.js\";\n\n/**\n * Ed25519-Signaturen für Lizenzen und Grants.\n *\n * Der Server signiert mit dem privaten Seed (nur in config.php / KeePass),\n * der Client prüft ausschliesslich mit dem öffentlichen Schlüssel. Wer das CLI\n * besitzt, kann damit nichts ausstellen. Schlüssel sind rohe 32 Byte, base64.\n *\n * Jeder Token-Typ signiert mit eigenem Domain-Präfix, damit eine Lizenz-\n * Signatur nie als Grant (oder umgekehrt) durchgeht.\n */\nexport type SignDomain = \"cpcg-license-v1\" | \"cpcg-grant-v1\";\n\nconst PKCS8_PREFIX = Buffer.from(\"302e020100300506032b657004220420\", \"hex\");\nconst SPKI_PREFIX = Buffer.from(\"302a300506032b6570032100\", \"hex\");\n\nfunction rawKey(b64: string, what: string): Buffer {\n const raw = Buffer.from(b64, \"base64\");\n if (raw.length !== 32) throw new Error(`${what}: erwartet 32 Byte (base64), erhalten ${raw.length}`);\n return raw;\n}\n\nexport function generateLicenseKeyPair(): { seed: string; publicKey: string } {\n const { privateKey, publicKey } = crypto.generateKeyPairSync(\"ed25519\");\n return {\n seed: privateKey.export({ format: \"der\", type: \"pkcs8\" }).subarray(-32).toString(\"base64\"),\n publicKey: publicKey.export({ format: \"der\", type: \"spki\" }).subarray(-32).toString(\"base64\"),\n };\n}\n\nexport function signEd25519(domain: SignDomain, payload: string, seedB64: string): string {\n const key = crypto.createPrivateKey({\n key: Buffer.concat([PKCS8_PREFIX, rawKey(seedB64, \"CPCG_LICENSE_SIGNING_SEED\")]),\n format: \"der\",\n type: \"pkcs8\",\n });\n return crypto.sign(null, Buffer.from(`${domain}.${payload}`), key).toString(\"base64url\");\n}\n\n/** Öffentlicher Schlüssel: CPCG_LICENSE_PUBLIC_KEY (Tests, Self-Hosting) vor dem eingebetteten. */\nexport function defaultPublicKey(): string {\n return process.env.CPCG_LICENSE_PUBLIC_KEY || LICENSE_PUBLIC_KEY;\n}\n\nexport function verifyEd25519(\n domain: SignDomain,\n payload: string,\n sigB64url: string,\n publicKeyB64: string = defaultPublicKey()\n): boolean {\n try {\n const key = crypto.createPublicKey({\n key: Buffer.concat([SPKI_PREFIX, rawKey(publicKeyB64, \"Public Key\")]),\n format: \"der\",\n type: \"spki\",\n });\n const sig = Buffer.from(sigB64url, \"base64url\");\n return sig.length === 64 && crypto.verify(null, Buffer.from(`${domain}.${payload}`), key, sig);\n } catch {\n return false;\n }\n}\n","/**\n * Öffentlicher Ed25519-Schlüssel des Cuonztech-Lizenzdienstes (32 Byte, base64).\n * Der zugehörige private Seed liegt nur serverseitig (config.php) und im KeePass.\n */\nexport const LICENSE_PUBLIC_KEY = \"q20XyLRZGURVvMLR6q0SCIc6poLhW73KE5Ds94Yq1FQ=\";\n"],"mappings":";AAAA,OAAO,YAAY;;;ACIZ,IAAM,qBAAqB;;;ADWlC,IAAM,eAAe,OAAO,KAAK,oCAAoC,KAAK;AAC1E,IAAM,cAAc,OAAO,KAAK,4BAA4B,KAAK;AAEjE,SAAS,OAAO,KAAa,MAAsB;AACjD,QAAM,MAAM,OAAO,KAAK,KAAK,QAAQ;AACrC,MAAI,IAAI,WAAW,GAAI,OAAM,IAAI,MAAM,GAAG,IAAI,yCAAyC,IAAI,MAAM,EAAE;AACnG,SAAO;AACT;AAoBO,SAAS,mBAA2B;AACzC,SAAO,QAAQ,IAAI,2BAA2B;AAChD;AAEO,SAAS,cACd,QACA,SACA,WACA,eAAuB,iBAAiB,GAC/B;AACT,MAAI;AACF,UAAM,MAAM,OAAO,gBAAgB;AAAA,MACjC,KAAK,OAAO,OAAO,CAAC,aAAa,OAAO,cAAc,YAAY,CAAC,CAAC;AAAA,MACpE,QAAQ;AAAA,MACR,MAAM;AAAA,IACR,CAAC;AACD,UAAM,MAAM,OAAO,KAAK,WAAW,WAAW;AAC9C,WAAO,IAAI,WAAW,MAAM,OAAO,OAAO,MAAM,OAAO,KAAK,GAAG,MAAM,IAAI,OAAO,EAAE,GAAG,KAAK,GAAG;AAAA,EAC/F,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}