@slashgear/gdpr-cookie-scanner 3.3.0 → 3.5.0

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 (46) hide show
  1. package/.github/workflows/ci.yml +20 -1
  2. package/.github/workflows/update-cookie-db.yml +94 -0
  3. package/CHANGELOG.md +130 -0
  4. package/CLAUDE.md +18 -0
  5. package/NEXT_STEPS.md +0 -25
  6. package/README.md +25 -24
  7. package/dist/classifiers/cookie-lookup.d.ts +8 -0
  8. package/dist/classifiers/cookie-lookup.d.ts.map +1 -0
  9. package/dist/classifiers/cookie-lookup.js +50 -0
  10. package/dist/classifiers/cookie-lookup.js.map +1 -0
  11. package/dist/cli.js +6 -5
  12. package/dist/cli.js.map +1 -1
  13. package/dist/data/open-cookie-database.json +25614 -0
  14. package/dist/index.d.ts +3 -1
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js.map +1 -1
  17. package/dist/report/generator.d.ts +1 -0
  18. package/dist/report/generator.d.ts.map +1 -1
  19. package/dist/report/generator.js +100 -4
  20. package/dist/report/generator.js.map +1 -1
  21. package/dist/report/html.d.ts.map +1 -1
  22. package/dist/report/html.js +16 -2
  23. package/dist/report/html.js.map +1 -1
  24. package/dist/scanner/consent-modal.d.ts +14 -1
  25. package/dist/scanner/consent-modal.d.ts.map +1 -1
  26. package/dist/scanner/consent-modal.js +148 -32
  27. package/dist/scanner/consent-modal.js.map +1 -1
  28. package/dist/scanner/index.d.ts.map +1 -1
  29. package/dist/scanner/index.js +11 -2
  30. package/dist/scanner/index.js.map +1 -1
  31. package/dist/types.d.ts +4 -1
  32. package/dist/types.d.ts.map +1 -1
  33. package/package.json +4 -3
  34. package/scripts/copy-data.mjs +4 -0
  35. package/scripts/update-cookie-db.mjs +15 -0
  36. package/src/classifiers/cookie-lookup.ts +72 -0
  37. package/src/cli.ts +13 -5
  38. package/src/data/open-cookie-database.json +25614 -0
  39. package/src/index.ts +3 -1
  40. package/src/report/generator.ts +119 -6
  41. package/src/report/html.ts +16 -2
  42. package/src/scanner/consent-modal.ts +169 -32
  43. package/src/scanner/index.ts +11 -2
  44. package/src/types.ts +4 -1
  45. package/tests/scanner/button-classification.test.ts +241 -0
  46. package/tests/scanner/contrast-ratio.test.ts +172 -0
@@ -43,4 +43,23 @@ jobs:
43
43
  run: pnpm exec playwright install chromium --with-deps
44
44
 
45
45
  - name: Test
46
- run: pnpm test
46
+ id: test
47
+ run: |
48
+ start=$(date +%s)
49
+ pnpm test
50
+ echo "duration=$(( $(date +%s) - start ))" >> "$GITHUB_OUTPUT"
51
+
52
+ - name: Record test suite duration
53
+ if: always()
54
+ run: |
55
+ duration="${{ steps.test.outputs.duration }}"
56
+ echo "## Test suite duration" >> "$GITHUB_STEP_SUMMARY"
57
+ echo "" >> "$GITHUB_STEP_SUMMARY"
58
+ echo "| Suite | Duration |" >> "$GITHUB_STEP_SUMMARY"
59
+ echo "| ----- | -------- |" >> "$GITHUB_STEP_SUMMARY"
60
+ echo "| unit + e2e | ${duration}s |" >> "$GITHUB_STEP_SUMMARY"
61
+ if [ "${duration:-0}" -gt 300 ]; then
62
+ echo "" >> "$GITHUB_STEP_SUMMARY"
63
+ echo "> [!WARNING]" >> "$GITHUB_STEP_SUMMARY"
64
+ echo "> Suite exceeded 300 s — possible performance regression." >> "$GITHUB_STEP_SUMMARY"
65
+ fi
@@ -0,0 +1,94 @@
1
+ name: Update Cookie DB
2
+
3
+ on:
4
+ schedule:
5
+ # 1st of every month at 04:00 UTC
6
+ - cron: "0 4 1 * *"
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ update:
11
+ runs-on: ubuntu-latest
12
+ permissions:
13
+ contents: write
14
+ pull-requests: write
15
+
16
+ steps:
17
+ - uses: actions/checkout@v6
18
+
19
+ - uses: pnpm/action-setup@v4
20
+ with:
21
+ version: latest
22
+
23
+ - uses: actions/setup-node@v4
24
+ with:
25
+ node-version: 24
26
+ cache: pnpm
27
+
28
+ - name: Install dependencies
29
+ run: pnpm install --frozen-lockfile
30
+
31
+ - name: Fetch Open Cookie Database
32
+ run: pnpm update:ocd
33
+
34
+ - name: Detect changes
35
+ id: diff
36
+ run: |
37
+ git diff --quiet src/data/open-cookie-database.json \
38
+ && echo "changed=false" >> "$GITHUB_OUTPUT" \
39
+ || echo "changed=true" >> "$GITHUB_OUTPUT"
40
+
41
+ - name: Type-check
42
+ if: steps.diff.outputs.changed == 'true'
43
+ run: pnpm typecheck
44
+
45
+ - name: Format
46
+ if: steps.diff.outputs.changed == 'true'
47
+ run: pnpm format
48
+
49
+ - name: Create PR
50
+ if: steps.diff.outputs.changed == 'true'
51
+ env:
52
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
53
+ run: |
54
+ BRANCH="chore/cookie-db-$(date +%Y%m)"
55
+ DATE="$(date +%Y-%m-%d)"
56
+ SLUG="cookie-db-update-${DATE}"
57
+
58
+ git config user.name "github-actions[bot]"
59
+ git config user.email "github-actions[bot]@users.noreply.github.com"
60
+ git checkout -b "$BRANCH"
61
+
62
+ # Write changeset
63
+ cat > ".changeset/${SLUG}.md" << EOF
64
+ ---
65
+ "@slashgear/gdpr-cookie-scanner": patch
66
+ ---
67
+
68
+ chore: monthly Open Cookie Database update
69
+ EOF
70
+
71
+ git add src/data/open-cookie-database.json ".changeset/${SLUG}.md"
72
+ git commit -m "chore: update Open Cookie Database"
73
+ git push origin "$BRANCH"
74
+
75
+ gh pr create \
76
+ --title "chore: monthly Open Cookie Database update ($(date +%B %Y))" \
77
+ --body "$(cat <<'BODY'
78
+ ## Summary
79
+
80
+ Automated monthly update of `src/data/open-cookie-database.json`.
81
+
82
+ - **Source**: [Open Cookie Database](https://github.com/jkwakman/Open-Cookie-Database) (Apache 2.0)
83
+ - Cookie descriptions are used to pre-fill the Description column in reports.
84
+
85
+ ## Test plan
86
+
87
+ - [ ] `pnpm typecheck` passes (validated by CI)
88
+ - [ ] `pnpm build` produces `dist/data/open-cookie-database.json`
89
+ - [ ] Spot-check a few cookie descriptions in the updated file
90
+
91
+ 🤖 Generated with [Claude Code](https://claude.com/claude-code)
92
+ BODY
93
+ )" \
94
+ --base main
package/CHANGELOG.md CHANGED
@@ -1,5 +1,135 @@
1
1
  # @slashgear/gdpr-cookie-scanner
2
2
 
3
+ ## 3.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - f41d0a0: feat: pre-fill cookie descriptions from Open Cookie Database and add CSV output format
8
+
9
+ Cookie reports now automatically include descriptions, platform names, retention
10
+ periods, and privacy-policy links for ~2 000+ recognised cookies, sourced from the
11
+ Open Cookie Database (Apache 2.0, vendored at `src/data/open-cookie-database.json`).
12
+
13
+ Previously the Description column in the Markdown cookie inventory was left as a
14
+ `<!-- fill in -->` placeholder. It is now pre-populated whenever the OCD contains a
15
+ matching entry (exact name or wildcard prefix), with the placeholder kept only for
16
+ unrecognised cookies.
17
+
18
+ The same enrichment is applied to the HTML report (new Description column in every
19
+ cookie table, with the platform and privacy-policy link surfaced in a tooltip) and to
20
+ the new `csv` output format (`gdpr-cookies-*.csv`), which includes all cookie
21
+ metadata plus the OCD fields in a machine-readable file suitable for DPA submissions
22
+ or spreadsheet review.
23
+
24
+ A `pnpm update:ocd` script and a monthly GitHub Actions workflow
25
+ (`.github/workflows/update-cookie-db.yml`) keep the vendored database up to date.
26
+
27
+ ### Patch Changes
28
+
29
+ - b88dad5: fix: truncate long cookie names with ellipsis in HTML cookie tables
30
+
31
+ Cookie names that contain URLs or other unusually long strings (e.g. Optimizely
32
+ session keys) were breaking the table layout in the HTML report. The Name column
33
+ now clamps to 220 px with `text-overflow: ellipsis`; hovering the cell reveals
34
+ the full name via the `title` attribute.
35
+
36
+ ## 3.4.0
37
+
38
+ ### Minor Changes
39
+
40
+ - 39794dc: Crop consent modal screenshot to the element; make after-reject/accept screenshots opt-in.
41
+
42
+ Two behaviour changes:
43
+
44
+ **Modal screenshot is now always captured (cropped)**
45
+ The consent modal screenshot (`modal-initial.png`) is taken whenever a modal
46
+ is detected and `outputDir` is set, regardless of the `--screenshots` flag.
47
+ The screenshot is clipped to the bounding box of the modal element instead of
48
+ capturing the full viewport, giving a tighter, more readable image. If the
49
+ bounding box cannot be determined (rare), it falls back to the viewport
50
+ screenshot.
51
+
52
+ **`--no-screenshots` replaced by `--screenshots`**
53
+ Previously all three screenshots were enabled by default and `--no-screenshots`
54
+ opted out. Now only the modal screenshot is taken by default; passing
55
+ `--screenshots` additionally captures `after-reject.png` and `after-accept.png`
56
+ (full viewport, as before). The `screenshots` field in `ScanOptions` / the
57
+ programmatic API retains the same type (`boolean`) with updated semantics:
58
+ `false` (default) = modal only; `true` = modal + after-reject + after-accept.
59
+
60
+ - 6a71a18: Add multi-language consent button detection (de, es, it, nl, pl, pt).
61
+
62
+ Previously, button classification only covered French and English, causing
63
+ false "no reject button" findings on sites served in other EU locales.
64
+
65
+ The fix has two parts:
66
+
67
+ 1. **Locale-aware pattern map** — `ACCEPT_PATTERNS` / `REJECT_PATTERNS` /
68
+ `PREFERENCES_PATTERNS` are replaced by a `PATTERNS_BY_LOCALE` map keyed by
69
+ BCP 47 primary subtag, covering `en`, `fr`, `de`, `es`, `it`, `nl`, `pl`,
70
+ `pt`. Polish patterns use a negative lookbehind instead of `\b` because
71
+ several Polish words end in non-ASCII characters (ć, ę, ó) that fall
72
+ outside JS `\w`.
73
+
74
+ 2. **`<html lang>` detection** — `detectConsentModal` now reads the page's
75
+ declared language from `document.documentElement.lang` and normalises it to
76
+ a primary subtag (e.g. `"de-DE"` → `"de"`). When the language is
77
+ recognised, only that locale's patterns plus English (universal fallback)
78
+ are tested. When the language is missing or unsupported, all available
79
+ patterns are tried — preserving the previous behaviour for unknown pages.
80
+
81
+ The public export `classifyButtonText(text, lang)` is added for testing and
82
+ programmatic use; 56 new unit tests cover every supported locale.
83
+
84
+ ### Patch Changes
85
+
86
+ - ceed240: Add unit tests for `computeContrastRatio`, `parseRgb`, and `relativeLuminance`.
87
+
88
+ These three pure functions in `consent-modal.ts` were previously only exercised
89
+ indirectly through the E2E suite. The new test file
90
+ (`tests/scanner/contrast-ratio.test.ts`) covers the happy path, edge cases
91
+ (identical colours, fully transparent rgba, non-integer ratios), and documents
92
+ the known limitations — named colours (`white`, `black`) and hex values (`#fff`)
93
+ return `null` until the parser is extended.
94
+
95
+ The functions are now exported so they can be imported by the test suite without
96
+ moving them to a separate module.
97
+
98
+ - df24a36: Fix consent modal detection for CMPs that start hidden (e.g. Axeptio).
99
+
100
+ `MODAL_SELECTORS` was a single flat list where every candidate was required to
101
+ pass `isVisible()`. CMPs such as Axeptio inject their overlay as `display:none`
102
+ during initialisation and reveal it via JS animation a few hundred milliseconds
103
+ later. The visibility check caused the scanner to skip `#axeptio_overlay` and
104
+ fall through to the first matching generic heuristic (e.g. `[id*='consent']`),
105
+ which could be a completely unrelated element.
106
+
107
+ The list is now split into two:
108
+
109
+ - **`CMP_SELECTORS`** — precise, platform-specific identifiers. DOM presence
110
+ alone is treated as a reliable signal. Once the element is found the scanner
111
+ waits up to 3 s for it to become visible (so button extraction sees an
112
+ interactive state) but proceeds regardless, preventing a slow CMP from
113
+ silently falling back to a wrong heuristic.
114
+ - **`HEURISTIC_SELECTORS`** — broad patterns that could match unrelated
115
+ elements. Visibility is still required to avoid false positives.
116
+
117
+ - f9efe0b: Normalise button text whitespace before classification.
118
+
119
+ `classifyButtonType` previously received raw `textContent` that had only been
120
+ `.trim()`-ed. CMP HTML templates frequently embed `&nbsp;` (U+00A0), newlines,
121
+ or tabs inside button labels, causing pattern matching to silently fail.
122
+
123
+ A `normalizeText` helper now collapses any whitespace sequence (including
124
+ U+00A0 and all Unicode spaces covered by JS `\s`) into a single ASCII space
125
+ before the regex is tested. The normalisation is applied in two places:
126
+
127
+ - `classifyButtonText` (public export) — defensive normalisation of any caller-
128
+ provided string.
129
+ - `extractButtons` — the raw `el.textContent()` result is normalised before
130
+ being stored in `ConsentButton.text` and before classification, so the
131
+ report also shows the cleaned label.
132
+
3
133
  ## 3.3.0
4
134
 
5
135
  ### Minor Changes
package/CLAUDE.md CHANGED
@@ -85,3 +85,21 @@ Grade thresholds: A ≥ 90, B ≥ 75, C ≥ 55, D ≥ 35, F < 35. Exit code 1 on
85
85
  ### Module system
86
86
 
87
87
  The project uses `"type": "module"` with `"moduleResolution": "NodeNext"`. All local imports **must** include the `.js` extension even for `.ts` source files.
88
+
89
+ ## Cookie database (Open Cookie Database)
90
+
91
+ The file `src/data/open-cookie-database.json` is vendored from
92
+ https://github.com/jkwakman/Open-Cookie-Database (Apache 2.0).
93
+
94
+ To update manually:
95
+
96
+ ```bash
97
+ pnpm update:ocd # fetches latest JSON, overwrites src/data/open-cookie-database.json
98
+ ```
99
+
100
+ A GitHub Actions workflow (`.github/workflows/update-cookie-db.yml`) runs this
101
+ automatically on the 1st of each month and opens a PR if the file changed.
102
+
103
+ The lookup module (`src/classifiers/cookie-lookup.ts`) builds an exact-match index
104
+ and a wildcard-prefix index at startup. `src/data/` is copied to `dist/data/` by
105
+ `scripts/copy-data.mjs` as part of the `pnpm build` step.
package/NEXT_STEPS.md CHANGED
@@ -14,25 +14,6 @@ Ideas and improvement areas for `gdpr-cookie-scanner`. Not a roadmap — pick wh
14
14
 
15
15
  ---
16
16
 
17
- ## Language support
18
-
19
- Currently only French and English patterns are covered. A lot of EU sites served in other locales will get false "no reject button" results.
20
-
21
- Languages to add at minimum (ordered by EU population / GDPR enforcement activity):
22
-
23
- | Locale | Reject examples | Accept examples |
24
- | ------- | ------------------------ | -------------------------------- |
25
- | `de-DE` | Ablehnen, Alle ablehnen | Alle akzeptieren, Zustimmen |
26
- | `es-ES` | Rechazar, Rechazar todo | Aceptar, Aceptar todo |
27
- | `it-IT` | Rifiuta, Rifiuta tutto | Accetta, Accetta tutto |
28
- | `nl-NL` | Weigeren, Alles weigeren | Accepteren, Alles accepteren |
29
- | `pl-PL` | Odrzuć, Odrzuć wszystkie | Zaakceptuj, Zaakceptuj wszystkie |
30
- | `pt-PT` | Rejeitar, Rejeitar tudo | Aceitar, Aceitar tudo |
31
-
32
- The patterns live in `src/scanner/consent-modal.ts`. A locale-aware pattern map keyed by BCP 47 tag would be cleaner than one giant regex.
33
-
34
- ---
35
-
36
17
  ## Dark pattern detection gaps
37
18
 
38
19
  Patterns that are explicitly listed in CNIL/EDPB guidelines but not yet detected:
@@ -81,12 +62,6 @@ Patterns that are explicitly listed in CNIL/EDPB guidelines but not yet detected
81
62
 
82
63
  - **Report output tests** — no tests currently validate the content of generated Markdown, HTML, or JSON files. Add snapshot tests for at least the JSON output and spot-checks for key sections in HTML.
83
64
 
84
- - **Contrast ratio unit tests** — `computeContrastRatio` is pure logic but only exercised through E2E tests. Deserves a dedicated unit test file covering edge cases (identical colours, transparent backgrounds, named/hex inputs once supported).
85
-
86
- - **Locale-specific button pattern tests** — once multi-language patterns land, add a test case per locale to prevent regressions.
87
-
88
- - **Performance baseline** — the E2E suite takes ~2 minutes. As features grow, tracking suite duration in CI would help catch regressions early.
89
-
90
65
  ---
91
66
 
92
67
  ## Infrastructure
package/README.md CHANGED
@@ -63,18 +63,18 @@ gdpr-scan scan <url> [options]
63
63
 
64
64
  ### Options
65
65
 
66
- | Option | Default | Description |
67
- | ------------------------ | ---------------- | ------------------------------------------------------------------------------------------------------------ |
68
- | `-o, --output <dir>` | `./gdpr-reports` | Output directory for the report |
69
- | `-t, --timeout <ms>` | `30000` | Navigation timeout |
70
- | `-f, --format <formats>` | `html` | Output formats: `md`, `html`, `json`, `pdf` (comma-separated) |
71
- | `--viewport <preset>` | `desktop` | Viewport preset: `desktop` (1280×900), `tablet` (768×1024), `mobile` (390×844) |
72
- | `--fail-on <threshold>` | `F` | Exit with code 1 if grade is below this letter (`A`/`B`/`C`/`D`/`F`) or score is below this number (`0–100`) |
73
- | `--json-summary` | — | Emit a machine-readable JSON line to stdout after the scan (parseable by `jq`) |
74
- | `--strict` | — | Treat unrecognised cookies and unknown third-party requests as requiring consent |
75
- | `--no-screenshots` | — | Disable screenshot capture |
76
- | `-l, --locale <locale>` | `fr-FR` | Browser locale |
77
- | `-v, --verbose` | — | Show full stack trace on error |
66
+ | Option | Default | Description |
67
+ | ------------------------ | ---------------- | --------------------------------------------------------------------------------------------------------------------------------- |
68
+ | `-o, --output <dir>` | `./gdpr-reports` | Output directory for the report |
69
+ | `-t, --timeout <ms>` | `30000` | Navigation timeout |
70
+ | `-f, --format <formats>` | `html` | Output formats: `md`, `html`, `json`, `pdf`, `csv` (comma-separated) |
71
+ | `--viewport <preset>` | `desktop` | Viewport preset: `desktop` (1280×900), `tablet` (768×1024), `mobile` (390×844) |
72
+ | `--fail-on <threshold>` | `F` | Exit with code 1 if grade is below this letter (`A`/`B`/`C`/`D`/`F`) or score is below this number (`0–100`) |
73
+ | `--json-summary` | — | Emit a machine-readable JSON line to stdout after the scan (parseable by `jq`) |
74
+ | `--strict` | — | Treat unrecognised cookies and unknown third-party requests as requiring consent |
75
+ | `--screenshots` | — | Also capture full-page screenshots after reject and accept interactions (the consent modal is always screenshotted when detected) |
76
+ | `-l, --locale <locale>` | `fr-FR` | Browser locale |
77
+ | `-v, --verbose` | — | Show full stack trace on error |
78
78
 
79
79
  ### Examples
80
80
 
@@ -85,14 +85,14 @@ gdpr-scan scan https://example.com
85
85
  # With custom output directory
86
86
  gdpr-scan scan https://example.com -o ./reports
87
87
 
88
- # Scan in English, without screenshots
89
- gdpr-scan scan https://example.com --locale en-US --no-screenshots
88
+ # Scan in English with full interaction screenshots (reject + accept)
89
+ gdpr-scan scan https://example.com --locale en-US --screenshots
90
90
 
91
91
  # Generate a Markdown report instead
92
92
  gdpr-scan scan https://example.com -f md
93
93
 
94
94
  # Generate all formats at once
95
- gdpr-scan scan https://example.com -f md,html,json,pdf
95
+ gdpr-scan scan https://example.com -f md,html,json,pdf,csv
96
96
 
97
97
  # Scan with a mobile viewport (390×844, iPhone UA)
98
98
  gdpr-scan scan https://example.com --viewport mobile
@@ -243,7 +243,7 @@ All fields of `ScanResult` — cookies, network requests, modal analysis, compli
243
243
  const result = await scan("https://example.com", {
244
244
  locale: "fr-FR", // browser locale, also controls report language
245
245
  timeout: 60_000, // navigation timeout in ms (default: 30 000)
246
- screenshots: true, // capture screenshots (requires outputDir)
246
+ screenshots: true, // also capture after-reject and after-accept screenshots (modal is always screenshotted)
247
247
  outputDir: "./reports", // where to save screenshots
248
248
  verbose: false, // log scanner phases to stdout
249
249
  viewport: "mobile", // 'desktop' (default) | 'tablet' | 'mobile'
@@ -262,7 +262,7 @@ const result = await scan("https://example.com", { locale: "fr-FR" });
262
262
  const generator = new ReportGenerator({
263
263
  url: result.url,
264
264
  outputDir: "./reports",
265
- formats: ["html", "json"], // 'md' | 'html' | 'json' | 'pdf'
265
+ formats: ["html", "json"], // 'md' | 'html' | 'json' | 'pdf' | 'csv'
266
266
  locale: "fr-FR",
267
267
  timeout: 30_000,
268
268
  screenshots: false,
@@ -300,14 +300,15 @@ A real Chromium browser loads the page, interacts with the consent modal (reject
300
300
 
301
301
  ## Generated reports
302
302
 
303
- Each scan produces up to 4 file types in `<output-dir>/<hostname>/`:
303
+ Each scan produces up to 5 file types in `<output-dir>/<hostname>/`:
304
304
 
305
- | Format | Files | Description |
306
- | ------ | -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
307
- | `md` | `gdpr-report-*.md`, `gdpr-checklist-*.md`, `gdpr-cookies-*.md` | Main compliance report, per-rule checklist with legal references, and deduplicated cookie inventory |
308
- | `html` | `gdpr-report-*.html` | Self-contained styled report — grade badge, score cards, dark-pattern issues, cookie and tracker tables. Opens in any browser, no dependencies |
309
- | `json` | `gdpr-report-*.json` | Full raw scan result for programmatic processing or CI integration |
310
- | `pdf` | `gdpr-report-*.pdf` | PDF built from the Markdown reports via Playwright |
305
+ | Format | Files | Description |
306
+ | ------ | -------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
307
+ | `md` | `gdpr-report-*.md`, `gdpr-checklist-*.md`, `gdpr-cookies-*.md` | Main compliance report, per-rule checklist with legal references, and deduplicated cookie inventory |
308
+ | `html` | `gdpr-report-*.html` | Self-contained styled report — grade badge, score cards, dark-pattern issues, cookie and tracker tables. Opens in any browser, no dependencies |
309
+ | `json` | `gdpr-report-*.json` | Full raw scan result for programmatic processing or CI integration |
310
+ | `pdf` | `gdpr-report-*.pdf` | PDF built from the Markdown reports via Playwright |
311
+ | `csv` | `gdpr-cookies-*.csv` | Deduplicated cookie inventory with OCD descriptions, platform, retention period and privacy link — ready for spreadsheet review or DPA submissions |
311
312
 
312
313
  All formats contain:
313
314
 
@@ -0,0 +1,8 @@
1
+ export interface OcdEntry {
2
+ description: string;
3
+ platform: string;
4
+ retentionPeriod: string;
5
+ privacyLink: string;
6
+ }
7
+ export declare function lookupCookie(name: string): OcdEntry | null;
8
+ //# sourceMappingURL=cookie-lookup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cookie-lookup.d.ts","sourceRoot":"","sources":["../../src/classifiers/cookie-lookup.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,QAAQ;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;CACrB;AA6CD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAiB1D"}
@@ -0,0 +1,50 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join, dirname } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ // Build indexes once at module load time
5
+ const exactIndex = new Map();
6
+ const wildcardEntries = [];
7
+ function buildIndexes() {
8
+ const dbPath = join(dirname(fileURLToPath(import.meta.url)), "../data/open-cookie-database.json");
9
+ const raw = JSON.parse(readFileSync(dbPath, "utf-8"));
10
+ for (const entries of Object.values(raw)) {
11
+ for (const e of entries) {
12
+ if (!e.cookie)
13
+ continue;
14
+ const ocdEntry = {
15
+ description: e.description,
16
+ platform: e.dataController,
17
+ retentionPeriod: e.retentionPeriod,
18
+ privacyLink: e.privacyLink,
19
+ };
20
+ if (e.wildcardMatch === "1") {
21
+ wildcardEntries.push({ prefix: e.cookie.toLowerCase(), entry: ocdEntry });
22
+ }
23
+ else {
24
+ const key = e.cookie.toLowerCase();
25
+ if (!exactIndex.has(key)) {
26
+ exactIndex.set(key, ocdEntry);
27
+ }
28
+ }
29
+ }
30
+ }
31
+ }
32
+ buildIndexes();
33
+ export function lookupCookie(name) {
34
+ const lower = name.toLowerCase();
35
+ // 1. Exact match
36
+ const exact = exactIndex.get(lower);
37
+ if (exact)
38
+ return exact;
39
+ // 2. Wildcard prefix match (longest prefix wins)
40
+ let best = null;
41
+ let bestLen = 0;
42
+ for (const { prefix, entry } of wildcardEntries) {
43
+ if (lower.startsWith(prefix) && prefix.length > bestLen) {
44
+ best = entry;
45
+ bestLen = prefix.length;
46
+ }
47
+ }
48
+ return best;
49
+ }
50
+ //# sourceMappingURL=cookie-lookup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cookie-lookup.js","sourceRoot":"","sources":["../../src/classifiers/cookie-lookup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAqBzC,yCAAyC;AACzC,MAAM,UAAU,GAAG,IAAI,GAAG,EAAoB,CAAC;AAC/C,MAAM,eAAe,GAA+C,EAAE,CAAC;AAEvE,SAAS,YAAY;IACnB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,mCAAmC,CAAC,CAAC;IAClG,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAkC,CAAC;IAEvF,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QACzC,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,IAAI,CAAC,CAAC,CAAC,MAAM;gBAAE,SAAS;YACxB,MAAM,QAAQ,GAAa;gBACzB,WAAW,EAAE,CAAC,CAAC,WAAW;gBAC1B,QAAQ,EAAE,CAAC,CAAC,cAAc;gBAC1B,eAAe,EAAE,CAAC,CAAC,eAAe;gBAClC,WAAW,EAAE,CAAC,CAAC,WAAW;aAC3B,CAAC;YACF,IAAI,CAAC,CAAC,aAAa,KAAK,GAAG,EAAE,CAAC;gBAC5B,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;YAC5E,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,GAAG,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;gBACnC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;oBACzB,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;gBAChC,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,YAAY,EAAE,CAAC;AAEf,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAEjC,iBAAiB;IACjB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACpC,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IAExB,iDAAiD;IACjD,IAAI,IAAI,GAAoB,IAAI,CAAC;IACjC,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,eAAe,EAAE,CAAC;QAChD,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,GAAG,OAAO,EAAE,CAAC;YACxD,IAAI,GAAG,KAAK,CAAC;YACb,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC;QAC1B,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
package/dist/cli.js CHANGED
@@ -16,10 +16,10 @@ program
16
16
  .argument("<url>", "URL of the website to scan")
17
17
  .option("-o, --output <dir>", "Output directory for the report", "./gdpr-reports")
18
18
  .option("-t, --timeout <ms>", "Navigation timeout in milliseconds", "30000")
19
- .option("--no-screenshots", "Disable screenshot capture")
19
+ .option("--screenshots", "Capture full-page screenshots after reject and accept interactions (the consent modal is always screenshotted when detected)")
20
20
  .option("-l, --locale <locale>", "Browser locale for language detection", "fr-FR")
21
21
  .option("-v, --verbose", "Show detailed output", false)
22
- .option("-f, --format <formats>", "Output formats: md, html, json, pdf (comma-separated)", "html")
22
+ .option("-f, --format <formats>", "Output formats: md, html, json, pdf, csv (comma-separated)", "html")
23
23
  .option("--viewport <preset>", "Viewport preset: desktop (1280×900), tablet (768×1024), mobile (390×844)", "desktop")
24
24
  .option("--fail-on <threshold>", "Exit with code 1 if grade is below this letter (A/B/C/D/F) or score is below this number", "F")
25
25
  .option("--json-summary", "Emit a JSON summary line to stdout after the scan (machine-readable)", false)
@@ -41,20 +41,20 @@ program
41
41
  console.log(styleText("gray", ` Output : ${outputDir}`));
42
42
  console.log(styleText("gray", ` Viewport : ${viewport}`));
43
43
  console.log();
44
- const validFormats = new Set(["md", "html", "json", "pdf"]);
44
+ const validFormats = new Set(["md", "html", "json", "pdf", "csv"]);
45
45
  const formats = opts.format
46
46
  .split(",")
47
47
  .map((f) => f.trim().toLowerCase())
48
48
  .filter((f) => validFormats.has(f));
49
49
  if (formats.length === 0) {
50
- console.error(styleText("red", " Invalid --format value. Valid options: md, html, json, pdf"));
50
+ console.error(styleText("red", " Invalid --format value. Valid options: md, html, json, pdf, csv"));
51
51
  process.exit(2);
52
52
  }
53
53
  const options = {
54
54
  url: normalizedUrl,
55
55
  outputDir,
56
56
  timeout: parseInt(opts.timeout, 10),
57
- screenshots: opts.screenshots !== false,
57
+ screenshots: Boolean(opts.screenshots),
58
58
  locale: opts.locale,
59
59
  verbose: opts.verbose,
60
60
  formats,
@@ -90,6 +90,7 @@ program
90
90
  html: "HTML",
91
91
  json: "JSON",
92
92
  pdf: "PDF",
93
+ csv: "CSV",
93
94
  };
94
95
  for (const [fmt, path] of Object.entries(paths)) {
95
96
  console.log(styleText("green", ` ${(labels[fmt] ?? fmt).padEnd(8)} ${path}`));
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}