consent-engine 0.3.0__tar.gz → 0.3.2__tar.gz

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.
Files changed (60) hide show
  1. {consent_engine-0.3.0 → consent_engine-0.3.2}/PKG-INFO +1 -1
  2. {consent_engine-0.3.0 → consent_engine-0.3.2}/pyproject.toml +1 -1
  3. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/__init__.py +1 -1
  4. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/wiki/concepts/consent-mode-v2.md +67 -0
  5. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/wiki/log.md +23 -0
  6. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/tools/tool_08_report_generator.py +17 -9
  7. {consent_engine-0.3.0 → consent_engine-0.3.2}/.gitignore +0 -0
  8. {consent_engine-0.3.0 → consent_engine-0.3.2}/LICENSE +0 -0
  9. {consent_engine-0.3.0 → consent_engine-0.3.2}/README.md +0 -0
  10. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/api.py +0 -0
  11. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/audit.py +0 -0
  12. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/cli.py +0 -0
  13. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/config.py +0 -0
  14. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/vendor_library/open-cookie-database.csv +0 -0
  15. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/vendor_library/vendors.json +0 -0
  16. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/wiki/CLAUDE.md +0 -0
  17. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/wiki/concepts/cipa-vppa.md +0 -0
  18. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/wiki/concepts/cmp-failures.md +0 -0
  19. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/wiki/concepts/dark-patterns.md +0 -0
  20. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/wiki/concepts/gpc-signal.md +0 -0
  21. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/wiki/concepts/ssgtm-risk.md +0 -0
  22. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/wiki/enforcement/emerging-trends.md +0 -0
  23. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/wiki/enforcement/gdpr-fines.md +0 -0
  24. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/wiki/enforcement/lawsuit-surge.md +0 -0
  25. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/wiki/enforcement/live-fines-db.md +0 -0
  26. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/wiki/enforcement/us-class-actions.md +0 -0
  27. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/wiki/enforcement/us-enforcement.md +0 -0
  28. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/wiki/index.md +0 -0
  29. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/wiki/regulations/ccpa.md +0 -0
  30. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/wiki/regulations/gdpr.md +0 -0
  31. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/wiki/regulations/quebec-law25.md +0 -0
  32. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/wiki/regulations/tcf.md +0 -0
  33. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/wiki/regulations/us-state-laws.md +0 -0
  34. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/wiki/technical/cmp-profiles.md +0 -0
  35. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/wiki/technical/consent-mode-impact.md +0 -0
  36. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/wiki/technical/google-tag-gateway.md +0 -0
  37. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/data/wiki/technical/scanner-methodology.md +0 -0
  38. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/llm/__init__.py +0 -0
  39. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/llm/client.py +0 -0
  40. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/mcp_server.py +0 -0
  41. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/models/__init__.py +0 -0
  42. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/models/audit_request.py +0 -0
  43. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/models/audit_result.py +0 -0
  44. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/models/scan_result.py +0 -0
  45. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/models/vendor.py +0 -0
  46. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/templates/audit_deck.marp.md.j2 +0 -0
  47. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/templates/audit_report.html.j2 +0 -0
  48. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/tools/__init__.py +0 -0
  49. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/tools/cmp_clicker.py +0 -0
  50. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/tools/cmp_detector.py +0 -0
  51. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/tools/cmp_injector.py +0 -0
  52. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/tools/jurisdiction_detector.py +0 -0
  53. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/tools/tool_01_gtm_parser.py +0 -0
  54. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/tools/tool_02_violation_classifier.py +0 -0
  55. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/tools/tool_03_browser_scanner.py +0 -0
  56. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/tools/tool_04_har_analyzer.py +0 -0
  57. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/tools/tool_05_vendor_library.py +0 -0
  58. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/tools/tool_06_ssgtm_detector.py +0 -0
  59. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/tools/tool_06b_pixel_detector.py +0 -0
  60. {consent_engine-0.3.0 → consent_engine-0.3.2}/src/consent_engine/tools/tool_07_rag_retriever.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: consent-engine
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: Forensic consent-compliance audit engine. Deterministic by design.
5
5
  Project-URL: Homepage, https://github.com/kb223/consent-engine
6
6
  Project-URL: Repository, https://github.com/kb223/consent-engine
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "consent-engine"
7
- version = "0.3.0"
7
+ version = "0.3.2"
8
8
  description = "Forensic consent-compliance audit engine. Deterministic by design."
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -8,4 +8,4 @@ Public package surface:
8
8
  - consent_engine.llm.client LiteLLM-wrapped chat surface (agentic layer)
9
9
  """
10
10
 
11
- __version__ = "0.3.0"
11
+ __version__ = "0.3.2"
@@ -124,3 +124,70 @@ Non-compliant advertisers face:
124
124
  Sending any network request (which exposes IP addresses) before explicit consent may carry legal risk under strict interpretations of GDPR and Quebec Law 25. The transmission of cookieless pings requires a defensible legal basis — typically documented legitimate interest for aggregate modeling.
125
125
 
126
126
  An audit finding of `gcs=G100` with conversion events = data flowing to Google for modeling. This is not a clean pass — it requires documentation of the legal basis used.
127
+
128
+ ## Source Verification — Google's Official Documentation (re-verified 2026-05-18)
129
+
130
+ The "no cookies written when consent denied" rule is the load-bearing claim
131
+ behind the scanner's `_ga`+`GCS=G100` = ACM-misconfiguration classification.
132
+ Re-verified against Google's official docs:
133
+
134
+ | Claim | Google source | Direct evidence |
135
+ |---|---|---|
136
+ | `_ga` / `_ga_<id>` cookies are not written when `analytics_storage` is denied | [Consent mode reference](https://support.google.com/analytics/answer/13802165) + [About consent mode](https://support.google.com/analytics/answer/10000067) | "When visitors deny consent, consent-aware tags do not store cookies. Instead, tags communicate consent state and user activity by sending measurements without cookies (web), or signals (apps)" |
137
+ | Advanced Mode sends cookieless pings, not cookies | [Consent mode overview](https://developers.google.com/tag-platform/security/concepts/consent-mode) | "tags load with default settings and adjust behavior based on consent... If consent is denied, Google receives cookieless pings" |
138
+ | `_gcl_au` is not written when `ad_storage` is denied | [Set up consent mode](https://developers.google.com/tag-platform/security/guides/consent) | "If ad_storage is denied, Google tags won't save this information locally. Existing first-party advertising cookies won't be read." |
139
+ | `ads_data_redaction` deletes stored info on top of the cookie-write block | [Consent mode reference (Google Ads)](https://support.google.com/google-ads/answer/13802165) | "If you enable ads_data_redaction, when the user denies consent, Google Ads will delete the stored information" |
140
+ | URL passthrough is the cookieless alternative for cross-page analytics | [Set up consent mode](https://developers.google.com/tag-platform/security/guides/consent) | "If analytics_storage is set to denied, URL passthrough can be used to send event and session-based analytics (including key events) without cookies across pages" |
141
+
142
+ ### Scanner classifier implication (load-bearing)
143
+
144
+ The above is what makes `_ga` (or `_ga_<id>`) **+** `GCS=G100` on a fresh-context
145
+ scan a real config error and not "ACM working as designed":
146
+
147
+ - `GCS=G100` in the request payload proves the cookieless-ping layer is
148
+ active (Google's server sees a denied state).
149
+ - A fresh browser context has no pre-existing `_ga` cookies.
150
+ - If `_ga` appears after the scan, GA4 wrote it during this denied-consent
151
+ visit. Per the Google sources above, that is **not** ACM-compliant behavior.
152
+
153
+ The scanner classifies this as `confirmed_violation` with notes that frame
154
+ it as **"Advanced Consent Mode misconfiguration — cookieless-ping layer
155
+ firing correctly, cookie-suppression layer broken."** This is technically
156
+ distinct from a non-Google vendor firing without consent (no ACM equivalent
157
+ exists for Meta, TikTok, LinkedIn, etc.) — both are violations under denied
158
+ consent, but the fix paths differ and the report copy reflects that.
159
+
160
+ ### What this rule does NOT say
161
+
162
+ - It does **not** say `_ga_<id>` (the GA4-property-specific session cookie)
163
+ is always blocked. Some non-ACM implementations may set it; the audit
164
+ flags those.
165
+ - It does **not** apply to non-Google vendors. Meta, TikTok, LinkedIn, etc.
166
+ must be fully blocked when consent is denied — no cookieless-ping
167
+ equivalent exists for them.
168
+ - It does **not** mean GCS=G100 is itself a "clean pass." See the
169
+ *Regulatory Gray Area* section above on EU/Quebec exposure from any
170
+ pre-consent network request.
171
+
172
+ ### Session-continuity (consent revocation) — separate methodology
173
+
174
+ Two distinct cookie-behavior questions exist under ACM with denied consent:
175
+
176
+ 1. **Fresh-context denied — "should cookies be SET?"**
177
+ *Answer per Google: no.* Tested by this scanner via the S3 methodology
178
+ (fresh browser context, denial pre-injected, page loaded). `_ga` + GCS=G100
179
+ here = the cookie-suppression layer of ACM is broken.
180
+
181
+ 2. **Session-continuity withdrawal — "should previously-granted cookies be CLEARED when the user revokes?"**
182
+ *Answer per Google:* (a) **Not read** — "existing first-party advertising
183
+ cookies won't be read" once `ad_storage` is denied. (b) **Deleted** if and
184
+ only if `ads_data_redaction=true` is set on the page — "Google Ads will
185
+ delete the stored information." Without `ads_data_redaction`, prior cookies
186
+ persist on disk but are not used.
187
+
188
+ The current scanner tests question #1 only (fresh-context S3). Question #2
189
+ requires a session-continuity scan mode — granted → revoked mid-session —
190
+ that has not been built yet. Per the project's `concepts/consent-mode-v2.md`,
191
+ this distinction is recorded so buyers can interpret the scope correctly:
192
+ this audit confirms compliant cookie-write behavior under denied consent at
193
+ page load, not compliant cookie-clearance behavior on consent withdrawal.
@@ -4,6 +4,29 @@ Format: `## [YYYY-MM-DD] operation | description`
4
4
 
5
5
  ---
6
6
 
7
+ ## [2026-05-18] verify | ACM cookie behavior re-checked against Google official docs
8
+
9
+ Triggered by Kenneth's pushback on whether cookies-in-anonymous-state under
10
+ Advanced Consent Mode count as a violation. Fact-checked via WebSearch
11
+ against the official Google sources listed below; all five confirmed the
12
+ "no cookies written when consent denied" rule that the scanner's classifier
13
+ relies on.
14
+
15
+ Sources cross-checked (all from official Google domains):
16
+ - https://developers.google.com/tag-platform/security/concepts/consent-mode
17
+ - https://developers.google.com/tag-platform/security/guides/consent
18
+ - https://support.google.com/analytics/answer/13802165 (Consent mode reference)
19
+ - https://support.google.com/analytics/answer/10000067 (About consent mode)
20
+ - https://support.google.com/google-ads/answer/13802165 (Consent mode reference – Ads)
21
+
22
+ Page updated: `concepts/consent-mode-v2.md` — added a *Source Verification*
23
+ section with direct quotes mapped to each load-bearing claim, and a
24
+ *Scanner classifier implication* paragraph explaining why `_ga` + GCS=G100
25
+ on a fresh-context scan is a real config error (not "ACM working as
26
+ designed").
27
+
28
+ Outcome: scanner classification stands. Wiki is now the auditable record.
29
+
7
30
  ## [2026-04-08] ingest | Initial wiki build — 9 regulatory source docs
8
31
 
9
32
  Sources ingested from `data/regulatory/`:
@@ -1183,7 +1183,11 @@ def generate_marp_slides(
1183
1183
  else "None detected",
1184
1184
  _SVG_CROSS if pixel_violations else _SVG_CHECK,
1185
1185
  )
1186
- _gcs_code = f"<code style='background:#1f2937;padding:2px 6px;border-radius:3px;font-size:0.9em;'>{gcs_state}</code>"
1186
+ _gcs_code = (
1187
+ f"<code style='background:#faf8f2;color:#14182b;border:1px solid #e7e3d8;"
1188
+ f"padding:2px 8px;border-radius:3px;font-size:0.9em;"
1189
+ f"font-family:\"SF Mono\",Menlo,monospace;font-weight:600;'>{gcs_state}</code>"
1190
+ )
1187
1191
  if _gcs_full_denial:
1188
1192
  _gcs_display = f"{_gcs_code} — ACM implemented correctly (cookieless pings only)"
1189
1193
  _gcs_icon = _SVG_CHECK
@@ -1445,21 +1449,21 @@ def generate_marp_slides(
1445
1449
  )
1446
1450
 
1447
1451
  _gpc_footer = (
1448
- '<div style="margin-top:14px;background:#ffffff;border-radius:8px;padding:12px 16px;'
1452
+ '<div style="margin-top:10px;background:#faf8f2;border-radius:6px;padding:10px 14px;'
1449
1453
  f'border-left:3px solid {_gpc_verdict_color};">'
1450
- '<div style="font-size:0.68em;color:#9ca3af;line-height:1.6;">'
1451
- "Under CCPA/CPRA, GPC (Global Privacy Control) is a legally binding opt-out signal. "
1454
+ '<div style="font-size:0.62em;color:#6b7794;line-height:1.5;">'
1455
+ "Under CCPA/CPRA, GPC is a legally binding opt-out signal. "
1452
1456
  "California's CPPA has stated GPC non-compliance is enforceable without prior notice."
1453
1457
  "</div></div>"
1454
1458
  )
1455
1459
 
1456
1460
  _gpc_slide_md = (
1457
1461
  "---\n\n"
1462
+ "<!-- _class: compact -->\n\n"
1458
1463
  "### GPC COMPLIANCE TEST\n\n"
1459
1464
  f"# GPC Compliance {_gpc_tag_html}\n\n"
1460
- '<p style="font-size:0.75em;color:#9ca3af;margin-bottom:4px;">'
1461
- "Global Privacy Control signal test — Sec-GPC: 1 HTTP header plus "
1462
- "navigator.globalPrivacyControl = true injected on every request.</p>"
1465
+ '<p style="font-size:0.72em;color:#6b7794;margin:0 0 10px;line-height:1.5;">'
1466
+ "Sec-GPC: 1 header + navigator.globalPrivacyControl asserted on every request.</p>"
1463
1467
  f"{_gpc_rows}"
1464
1468
  f"{_gpc_footer}\n"
1465
1469
  )
@@ -1714,6 +1718,10 @@ style: |
1714
1718
  font-size: 0.82em; font-family: 'SF Mono', Menlo, monospace;
1715
1719
  }}
1716
1720
  section.lead {{ display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; }}
1721
+ section.compact {{ padding: 56px 96px 56px; }}
1722
+ section.compact h1 {{ font-size: 2.1em; margin-bottom: 8px; }}
1723
+ section.compact h2 {{ font-size: 1em; margin-bottom: 18px; }}
1724
+ section.compact p {{ font-size: 0.78em; }}
1717
1725
  section.cover {{ padding: 110px 96px; background: var(--bg); }}
1718
1726
  section.cover h1 {{
1719
1727
  font-size: 3.2em; border-left: 3px solid var(--a);
@@ -1843,11 +1851,11 @@ style: |
1843
1851
 
1844
1852
  ---
1845
1853
 
1846
- ### {_closing_kicker}
1854
+ ### PREPARED BY
1847
1855
 
1848
1856
  # Kenneth Buchanan
1849
1857
 
1850
- ## Consent Compliance Intelligence
1858
+ ## kennethjbuchanan.com
1851
1859
 
1852
1860
  <div style="display:flex;gap:10px;margin-top:28px;">
1853
1861
  <div style="flex:1;background:var(--s);border-radius:10px;padding:20px;border-top:2px solid var(--a);">
File without changes
File without changes