@slashgear/gdpr-cookie-scanner 1.0.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 (85) hide show
  1. package/.changeset/README.md +8 -0
  2. package/.changeset/config.json +11 -0
  3. package/.github/ISSUE_TEMPLATE/bug_report.yml +44 -0
  4. package/.github/ISSUE_TEMPLATE/feature_request.yml +26 -0
  5. package/.github/PULL_REQUEST_TEMPLATE.md +24 -0
  6. package/.github/workflows/ci.yml +38 -0
  7. package/.github/workflows/release.yml +57 -0
  8. package/.idea/gdpr-report.iml +8 -0
  9. package/.idea/modules.xml +8 -0
  10. package/.idea/vcs.xml +6 -0
  11. package/CHANGELOG.md +7 -0
  12. package/CLAUDE.md +75 -0
  13. package/CODE_OF_CONDUCT.md +41 -0
  14. package/CONTRIBUTING.md +79 -0
  15. package/LICENSE +21 -0
  16. package/README.md +127 -0
  17. package/SECURITY.md +15 -0
  18. package/dist/analyzers/compliance.d.ts +13 -0
  19. package/dist/analyzers/compliance.d.ts.map +1 -0
  20. package/dist/analyzers/compliance.js +171 -0
  21. package/dist/analyzers/compliance.js.map +1 -0
  22. package/dist/analyzers/wording.d.ts +13 -0
  23. package/dist/analyzers/wording.d.ts.map +1 -0
  24. package/dist/analyzers/wording.js +91 -0
  25. package/dist/analyzers/wording.js.map +1 -0
  26. package/dist/classifiers/cookie-classifier.d.ts +8 -0
  27. package/dist/classifiers/cookie-classifier.d.ts.map +1 -0
  28. package/dist/classifiers/cookie-classifier.js +108 -0
  29. package/dist/classifiers/cookie-classifier.js.map +1 -0
  30. package/dist/classifiers/network-classifier.d.ts +9 -0
  31. package/dist/classifiers/network-classifier.d.ts.map +1 -0
  32. package/dist/classifiers/network-classifier.js +51 -0
  33. package/dist/classifiers/network-classifier.js.map +1 -0
  34. package/dist/classifiers/tracker-list.d.ts +16 -0
  35. package/dist/classifiers/tracker-list.d.ts.map +1 -0
  36. package/dist/classifiers/tracker-list.js +86 -0
  37. package/dist/classifiers/tracker-list.js.map +1 -0
  38. package/dist/cli.d.ts +3 -0
  39. package/dist/cli.d.ts.map +1 -0
  40. package/dist/cli.js +110 -0
  41. package/dist/cli.js.map +1 -0
  42. package/dist/report/generator.d.ts +19 -0
  43. package/dist/report/generator.d.ts.map +1 -0
  44. package/dist/report/generator.js +552 -0
  45. package/dist/report/generator.js.map +1 -0
  46. package/dist/scanner/browser.d.ts +11 -0
  47. package/dist/scanner/browser.d.ts.map +1 -0
  48. package/dist/scanner/browser.js +38 -0
  49. package/dist/scanner/browser.js.map +1 -0
  50. package/dist/scanner/consent-modal.d.ts +5 -0
  51. package/dist/scanner/consent-modal.d.ts.map +1 -0
  52. package/dist/scanner/consent-modal.js +244 -0
  53. package/dist/scanner/consent-modal.js.map +1 -0
  54. package/dist/scanner/cookies.d.ts +11 -0
  55. package/dist/scanner/cookies.d.ts.map +1 -0
  56. package/dist/scanner/cookies.js +30 -0
  57. package/dist/scanner/cookies.js.map +1 -0
  58. package/dist/scanner/index.d.ts +9 -0
  59. package/dist/scanner/index.d.ts.map +1 -0
  60. package/dist/scanner/index.js +146 -0
  61. package/dist/scanner/index.js.map +1 -0
  62. package/dist/scanner/network.d.ts +8 -0
  63. package/dist/scanner/network.d.ts.map +1 -0
  64. package/dist/scanner/network.js +41 -0
  65. package/dist/scanner/network.js.map +1 -0
  66. package/dist/types.d.ts +105 -0
  67. package/dist/types.d.ts.map +1 -0
  68. package/dist/types.js +2 -0
  69. package/dist/types.js.map +1 -0
  70. package/package.json +52 -0
  71. package/renovate.json +17 -0
  72. package/src/analyzers/compliance.ts +203 -0
  73. package/src/analyzers/wording.ts +112 -0
  74. package/src/classifiers/cookie-classifier.ts +125 -0
  75. package/src/classifiers/network-classifier.ts +65 -0
  76. package/src/classifiers/tracker-list.ts +105 -0
  77. package/src/cli.ts +134 -0
  78. package/src/report/generator.ts +703 -0
  79. package/src/scanner/browser.ts +52 -0
  80. package/src/scanner/consent-modal.ts +276 -0
  81. package/src/scanner/cookies.ts +43 -0
  82. package/src/scanner/index.ts +163 -0
  83. package/src/scanner/network.ts +51 -0
  84. package/src/types.ts +134 -0
  85. package/tsconfig.json +18 -0
@@ -0,0 +1,8 @@
1
+ # Changesets
2
+
3
+ Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
4
+ with multi-package repos, or single-package repos to help you version and publish your code. You can
5
+ find the full documentation for it [in our repository](https://github.com/changesets/changesets)
6
+
7
+ We have a quick list of common questions to get you started engaging with this project in
8
+ [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
@@ -0,0 +1,11 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@changesets/config@3.1.2/schema.json",
3
+ "changelog": "@changesets/cli/changelog",
4
+ "commit": false,
5
+ "fixed": [],
6
+ "linked": [],
7
+ "access": "public",
8
+ "baseBranch": "main",
9
+ "updateInternalDependencies": "patch",
10
+ "ignore": []
11
+ }
@@ -0,0 +1,44 @@
1
+ name: Bug report
2
+ description: Report a problem with the scanner
3
+ labels: [bug]
4
+ body:
5
+ - type: input
6
+ id: url
7
+ attributes:
8
+ label: Scanned URL
9
+ description: The URL that caused the problem (optional if sensitive)
10
+ validations:
11
+ required: false
12
+
13
+ - type: textarea
14
+ id: description
15
+ attributes:
16
+ label: Problem description
17
+ description: What happened vs what was expected
18
+ validations:
19
+ required: true
20
+
21
+ - type: textarea
22
+ id: reproduce
23
+ attributes:
24
+ label: Command used
25
+ render: bash
26
+ placeholder: node dist/cli.js scan https://...
27
+ validations:
28
+ required: true
29
+
30
+ - type: textarea
31
+ id: output
32
+ attributes:
33
+ label: Output / error
34
+ render: text
35
+ validations:
36
+ required: false
37
+
38
+ - type: input
39
+ id: version
40
+ attributes:
41
+ label: Node.js version
42
+ placeholder: "e.g. 22.0.0"
43
+ validations:
44
+ required: true
@@ -0,0 +1,26 @@
1
+ name: Feature request
2
+ description: Suggest an improvement or a new RGPD rule
3
+ labels: [enhancement]
4
+ body:
5
+ - type: textarea
6
+ id: problem
7
+ attributes:
8
+ label: Problem or uncovered case
9
+ description: What situation does the scanner not currently handle?
10
+ validations:
11
+ required: true
12
+
13
+ - type: textarea
14
+ id: solution
15
+ attributes:
16
+ label: Proposed solution
17
+ validations:
18
+ required: true
19
+
20
+ - type: input
21
+ id: reference
22
+ attributes:
23
+ label: Legal reference (if applicable)
24
+ placeholder: "e.g. CNIL 2022, RGPD Art. 7, CEPD 03/2022"
25
+ validations:
26
+ required: false
@@ -0,0 +1,24 @@
1
+ ## Description
2
+
3
+ <!-- Describe the changes made -->
4
+
5
+ ## Type of change
6
+
7
+ - [ ] Bug fix
8
+ - [ ] New feature
9
+ - [ ] New tracker / cookie pattern
10
+ - [ ] CMP detection improvement
11
+ - [ ] Refactoring / performance
12
+ - [ ] Documentation
13
+
14
+ ## Checklist
15
+
16
+ - [ ] `pnpm format:check` passes
17
+ - [ ] `pnpm lint` passes
18
+ - [ ] `pnpm typecheck` passes
19
+ - [ ] `pnpm build` passes
20
+ - [ ] Manually tested on at least one site
21
+
22
+ ## Legal reference (if new rule)
23
+
24
+ <!-- E.g. CNIL 2022, RGPD Art. 7, CEPD 03/2022 -->
@@ -0,0 +1,38 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ ci:
11
+ runs-on: ubuntu-latest
12
+
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+
16
+ - uses: pnpm/action-setup@v4
17
+ with:
18
+ version: latest
19
+
20
+ - uses: actions/setup-node@v4
21
+ with:
22
+ node-version: 22
23
+ cache: pnpm
24
+
25
+ - name: Install dependencies
26
+ run: pnpm install --frozen-lockfile
27
+
28
+ - name: Format check
29
+ run: pnpm format:check
30
+
31
+ - name: Lint
32
+ run: pnpm lint
33
+
34
+ - name: Type check
35
+ run: pnpm typecheck
36
+
37
+ - name: Build
38
+ run: pnpm build
@@ -0,0 +1,57 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+
7
+ jobs:
8
+ release:
9
+ runs-on: ubuntu-latest
10
+ permissions:
11
+ contents: write
12
+ pull-requests: write
13
+ packages: write
14
+ id-token: write # required for npm trusted publishing (OIDC)
15
+
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - uses: pnpm/action-setup@v4
20
+ with:
21
+ version: latest
22
+
23
+ - uses: actions/setup-node@v4
24
+ with:
25
+ node-version: 22
26
+ cache: pnpm
27
+ registry-url: https://registry.npmjs.org
28
+
29
+ - name: Install dependencies
30
+ run: pnpm install --frozen-lockfile
31
+
32
+ - name: Build
33
+ run: pnpm build
34
+
35
+ - name: Create release PR or publish to npm
36
+ id: changesets
37
+ uses: changesets/action@v1
38
+ with:
39
+ publish: pnpm changeset publish
40
+ title: "chore: release new version"
41
+ commit: "chore: release new version"
42
+ env:
43
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
44
+ NPM_CONFIG_PROVENANCE: "true"
45
+
46
+ - name: Configure registry for GitHub Packages
47
+ if: steps.changesets.outputs.published == 'true'
48
+ uses: actions/setup-node@v4
49
+ with:
50
+ node-version: 22
51
+ registry-url: https://npm.pkg.github.com
52
+
53
+ - name: Publish to GitHub Packages
54
+ if: steps.changesets.outputs.published == 'true'
55
+ run: npm publish
56
+ env:
57
+ NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="WEB_MODULE" version="4">
3
+ <component name="NewModuleRootManager">
4
+ <content url="file://$MODULE_DIR$" />
5
+ <orderEntry type="inheritedJdk" />
6
+ <orderEntry type="sourceFolder" forTests="false" />
7
+ </component>
8
+ </module>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/gdpr-report.iml" filepath="$PROJECT_DIR$/.idea/gdpr-report.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
package/.idea/vcs.xml ADDED
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="" vcs="Git" />
5
+ </component>
6
+ </project>
package/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # @slashgear/gdpr-cookie-scanner
2
+
3
+ ## 1.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - Initial stable release — 4-phase GDPR compliance scanner with consent modal detection, dark pattern analysis, cookie/tracker behavior checks, and Markdown report + checklist generation.
package/CLAUDE.md ADDED
@@ -0,0 +1,75 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Commands
6
+
7
+ ```bash
8
+ pnpm build # Compile TypeScript → dist/
9
+ pnpm dev # Watch mode compilation
10
+ pnpm typecheck # Type-check without emitting
11
+ pnpm lint # oxlint
12
+ pnpm lint:fix # oxlint --fix
13
+ pnpm format # oxfmt (auto-format)
14
+ pnpm format:check # oxfmt --check (used in CI)
15
+
16
+ # Run the CLI after building
17
+ node dist/cli.js scan <url>
18
+ node dist/cli.js scan <url> -o ./reports --locale fr-FR --verbose
19
+ node dist/cli.js list-trackers
20
+ ```
21
+
22
+ There are no tests currently.
23
+
24
+ ## Release process
25
+
26
+ This project uses [Changesets](https://github.com/changesets/changesets).
27
+
28
+ - **Contributors**: run `pnpm changeset` before opening a PR to document the change (patch/minor/major + summary). Commit the generated `.changeset/*.md` file with your PR. Skip for docs/CI-only changes.
29
+ - **Maintainers**: merging changesets into `main` triggers the release workflow, which opens a "chore: release new version" PR (bumps version + updates `CHANGELOG.md`). Merging that PR publishes to GitHub Packages and creates the GitHub Release automatically.
30
+
31
+ Commits must follow [Conventional Commits](https://www.conventionalcommits.org/) (`feat:`, `fix:`, `chore:`, `docs:`, etc.).
32
+
33
+ ## Architecture
34
+
35
+ This is a TypeScript CLI tool (`gdpr-scan`) that audits websites for GDPR/RGPD cookie consent compliance using Playwright. It produces a Markdown report in French.
36
+
37
+ ### Scan pipeline (`src/scanner/index.ts`)
38
+
39
+ The scanner runs **4 sequential phases** using real Chromium browsers:
40
+
41
+ 1. **Phase 1** — Load page with no interaction; capture cookies + network requests (`before-interaction`)
42
+ 2. **Phase 2** — Detect the consent modal/banner (CSS selectors + heuristics)
43
+ 3. **Phase 3** — Click the reject button in the same session; capture state (`after-reject`)
44
+ 4. **Phase 4** — Fresh browser session, load page, click accept; capture state (`after-accept`)
45
+
46
+ Phase 3 and 4 require two separate browser sessions so cookie state is fully isolated.
47
+
48
+ ### Module responsibilities
49
+
50
+ - **`src/scanner/browser.ts`** — Playwright browser/context lifecycle helpers
51
+ - **`src/scanner/cookies.ts`** — Extract and classify cookies from Playwright context
52
+ - **`src/scanner/network.ts`** — Intercept and classify network requests via Playwright events
53
+ - **`src/scanner/consent-modal.ts`** — Detect consent modal by trying known CMP selectors (`MODAL_SELECTORS`) then falling back to DOM heuristics; extracts buttons/checkboxes with visual properties (font size, bounding box, contrast ratio) needed for dark-pattern detection
54
+ - **`src/classifiers/cookie-classifier.ts`** — Pattern-match cookie names against a static list to assign `CookieCategory` and `requiresConsent`
55
+ - **`src/classifiers/network-classifier.ts`** — Look up request hostnames in `TRACKER_DB` and match URL patterns against `PIXEL_PATTERNS`
56
+ - **`src/classifiers/tracker-list.ts`** — Static database of tracker domains by category
57
+ - **`src/analyzers/compliance.ts`** — Scores 4 dimensions (0–25 each) and surfaces `DarkPatternIssue` objects: consent validity, easy refusal, transparency, cookie behavior
58
+ - **`src/analyzers/wording.ts`** — Text analysis of button labels and modal copy
59
+ - **`src/report/generator.ts`** — Renders a Markdown report and checklist from `ScanResult`; runs `oxfmt` on generated files
60
+ - **`src/types.ts`** — All shared TypeScript interfaces (`ScanResult`, `ScanOptions`, `ComplianceScore`, `ConsentModal`, etc.)
61
+
62
+ ### Compliance scoring
63
+
64
+ Each of the 4 score dimensions starts at 25 and gets deducted based on detected issues:
65
+
66
+ - `consentValidity` — pre-ticked boxes, misleading wording, missing info
67
+ - `easyRefusal` — absent/buried reject button, click asymmetry, visual asymmetry
68
+ - `transparency` — no granular controls, missing info fields
69
+ - `cookieBehavior` — non-essential cookies/trackers before consent, consent-requiring cookies persisting after reject
70
+
71
+ Grade thresholds: A ≥ 90, B ≥ 75, C ≥ 55, D ≥ 35, F < 35. Exit code 1 on grade F.
72
+
73
+ ### Module system
74
+
75
+ The project uses `"type": "module"` with `"moduleResolution": "NodeNext"`. All local imports **must** include the `.js` extension even for `.ts` source files.
@@ -0,0 +1,41 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
6
+
7
+ We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
8
+
9
+ ## Our Standards
10
+
11
+ Examples of behavior that contributes to a positive environment:
12
+
13
+ - Demonstrating empathy and kindness toward other people
14
+ - Being respectful of differing opinions, viewpoints, and experiences
15
+ - Giving and gracefully accepting constructive feedback
16
+ - Accepting responsibility and apologizing to those affected by our mistakes
17
+ - Focusing on what is best not just for us as individuals, but for the overall community
18
+
19
+ Examples of unacceptable behavior:
20
+
21
+ - The use of sexualized language or imagery, and sexual attention or advances of any kind
22
+ - Trolling, insulting or derogatory comments, and personal or political attacks
23
+ - Public or private harassment
24
+ - Publishing others' private information without their explicit permission
25
+ - Other conduct which could reasonably be considered inappropriate in a professional setting
26
+
27
+ ## Enforcement Responsibilities
28
+
29
+ Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
30
+
31
+ ## Scope
32
+
33
+ This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces.
34
+
35
+ ## Enforcement
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening a [GitHub Security Advisory](https://github.com/Slashgear/gdpr-report/security/advisories/new). All complaints will be reviewed and investigated promptly and fairly.
38
+
39
+ ## Attribution
40
+
41
+ This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1.
@@ -0,0 +1,79 @@
1
+ # Contributing to gdpr-cookie-scanner
2
+
3
+ ## Prerequisites
4
+
5
+ - Node.js ≥ 20
6
+ - pnpm
7
+ - Playwright: `npx playwright install chromium`
8
+
9
+ ## Getting started
10
+
11
+ ```bash
12
+ git clone https://github.com/Slashgear/gdpr-report.git
13
+ cd gdpr-report
14
+ pnpm install
15
+ pnpm build
16
+
17
+ # Run the CLI locally
18
+ node dist/cli.js scan https://example.com
19
+ ```
20
+
21
+ ## Workflow
22
+
23
+ 1. Fork the repository and create a branch from `main`
24
+ 2. Make your changes
25
+ 3. Verify that CI passes locally:
26
+ ```bash
27
+ pnpm format:check
28
+ pnpm lint
29
+ pnpm typecheck
30
+ pnpm build
31
+ ```
32
+ 4. Open a Pull Request targeting `main`
33
+
34
+ ## Areas to contribute
35
+
36
+ - **Classifiers** — add cookie patterns or tracker domains in `src/classifiers/`
37
+ - **Consent modal detection** — improve CMP detection in `src/scanner/consent-modal.ts`
38
+ - **Compliance rules** — refine scoring rules in `src/analyzers/compliance.ts`
39
+ - **Report** — improve report rendering in `src/report/generator.ts`
40
+
41
+ ## Releasing
42
+
43
+ This project uses [Changesets](https://github.com/changesets/changesets) to manage versions and changelogs.
44
+
45
+ ### As a contributor — document your change
46
+
47
+ Every PR that changes behaviour (bug fix, new feature, breaking change) must include a changeset:
48
+
49
+ ```bash
50
+ pnpm changeset
51
+ ```
52
+
53
+ The interactive prompt asks:
54
+
55
+ - **Which packages** are affected (only one here: `@slashgear/gdpr-cookie-scanner`)
56
+ - **Bump type**: `patch` (bug fix) · `minor` (new feature) · `major` (breaking change)
57
+ - **Summary**: one-line description that will appear in `CHANGELOG.md`
58
+
59
+ This creates a file in `.changeset/` — commit it alongside your changes.
60
+
61
+ > PRs without a changeset are fine for docs, tests, or CI changes that don't affect the published package.
62
+
63
+ ### As a maintainer — publish a release
64
+
65
+ When changesets are merged into `main`, the [release workflow](.github/workflows/release.yml) automatically opens a **"chore: release new version"** PR that:
66
+
67
+ - Bumps `package.json` version
68
+ - Aggregates all changeset summaries into `CHANGELOG.md`
69
+
70
+ Merging that PR triggers the workflow again, which:
71
+
72
+ 1. Publishes `@slashgear/gdpr-cookie-scanner` to [GitHub Packages](https://github.com/Slashgear/gdpr-report/pkgs/npm/gdpr-cookie-scanner)
73
+ 2. Creates the corresponding GitHub Release with the generated changelog
74
+
75
+ ## Conventions
76
+
77
+ - Local imports must include the `.js` extension (ESM NodeNext module)
78
+ - Formatting is handled by oxfmt (`pnpm format`), do not format manually
79
+ - Commit messages follow the [Conventional Commits](https://www.conventionalcommits.org/) convention
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 gdpr-cookie-scanner contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,127 @@
1
+ # gdpr-cookie-scanner
2
+
3
+ [![CI](https://github.com/Slashgear/gdpr-report/actions/workflows/ci.yml/badge.svg)](https://github.com/Slashgear/gdpr-report/actions/workflows/ci.yml)
4
+ [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](CODE_OF_CONDUCT.md)
5
+
6
+ CLI tool to automatically audit the GDPR cookie consent compliance of a website: consent modal, dark patterns, cookies set before/after interaction, network trackers. Generates a detailed Markdown report.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm install -g @slashgear/gdpr-cookie-scanner
12
+ npx playwright install chromium
13
+ ```
14
+
15
+ Or run without installing:
16
+
17
+ ```bash
18
+ npx @slashgear/gdpr-cookie-scanner gdpr-scan scan https://example.com
19
+ # Playwright is still required the first time:
20
+ npx playwright install chromium
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ```bash
26
+ gdpr-scan scan <url> [options]
27
+ ```
28
+
29
+ ### Options
30
+
31
+ | Option | Default | Description |
32
+ | ----------------------- | ---------------- | ------------------------------- |
33
+ | `-o, --output <dir>` | `./gdpr-reports` | Output directory for the report |
34
+ | `-t, --timeout <ms>` | `30000` | Navigation timeout |
35
+ | `--no-screenshots` | — | Disable screenshot capture |
36
+ | `-l, --locale <locale>` | `fr-FR` | Browser locale |
37
+ | `-v, --verbose` | — | Show full stack trace on error |
38
+
39
+ ### Examples
40
+
41
+ ```bash
42
+ # Basic scan
43
+ gdpr-scan scan https://example.com
44
+
45
+ # With custom output directory
46
+ gdpr-scan scan https://example.com -o ./reports
47
+
48
+ # Scan in English, without screenshots
49
+ gdpr-scan scan https://example.com --locale en-US --no-screenshots
50
+
51
+ # Show the built-in tracker database
52
+ gdpr-scan list-trackers
53
+ ```
54
+
55
+ ## How it works
56
+
57
+ The scanner runs **4 phases** using a real Chromium browser (Playwright):
58
+
59
+ 1. **Initial load** — The page is loaded without any interaction. All cookies and network requests are captured (`before-interaction`).
60
+ 2. **Modal analysis** — The consent banner is detected (CSS selectors of known CMPs + DOM heuristics). Buttons are extracted with their visual properties (size, color, contrast ratio).
61
+ 3. **Reject test** — The "Reject" button is clicked. Cookies and requests are captured (`after-reject`).
62
+ 4. **Accept test** — A new browser session (clean state) loads the page and clicks "Accept". Cookies and requests are captured (`after-accept`).
63
+
64
+ ## Generated report
65
+
66
+ The Markdown report contains:
67
+
68
+ - **Global score** (0–100) and **grade** A/B/C/D/F
69
+ - Executive summary
70
+ - Modal analysis: buttons, checkboxes, font size, screenshots
71
+ - Detected dark patterns (missing reject button, visual asymmetry, pre-ticked boxes, misleading wording…)
72
+ - Cookie table before interaction, after reject, after accept
73
+ - Network tracker requests by phase
74
+ - Targeted recommendations
75
+ - Legal references (RGPD, ePrivacy directive, CEPD guidelines, CNIL 2022)
76
+
77
+ The file is created at: `<output-dir>/gdpr-report-<domain>-<date>.md`
78
+
79
+ ## Scoring
80
+
81
+ The score is made up of 4 criteria (25 points each):
82
+
83
+ | Criterion | What is evaluated |
84
+ | -------------------- | ---------------------------------------------------------------------------------------------- |
85
+ | **Consent validity** | Pre-ticked boxes, ambiguous wording, missing information |
86
+ | **Easy refusal** | Missing or buried reject button, click asymmetry, visual asymmetry |
87
+ | **Transparency** | Granular controls, mention of purposes / third parties / duration / right to withdraw |
88
+ | **Cookie behavior** | Non-essential cookies before consent, cookies persisting after reject, trackers before consent |
89
+
90
+ **Grade scale:** A ≥ 90 · B ≥ 75 · C ≥ 55 · D ≥ 35 · F < 35
91
+
92
+ The process exits with code `1` if the grade is F, `2` on scan error.
93
+
94
+ ## Detected dark patterns
95
+
96
+ | Type | Severity | Description |
97
+ | ----------------------- | ---------------- | ----------------------------------------------------- |
98
+ | `no-reject-button` | Critical | No reject option in the modal |
99
+ | `buried-reject` | Critical | Reject button not present at the first layer |
100
+ | `click-asymmetry` | Critical | Rejecting requires more clicks than accepting |
101
+ | `pre-ticked` | Critical | Pre-ticked checkboxes (invalid under RGPD Recital 32) |
102
+ | `auto-consent` | Critical | Non-essential cookies/trackers before any consent |
103
+ | `asymmetric-prominence` | Warning | Accept button significantly larger than reject |
104
+ | `nudging` | Warning | Accept button font larger than reject button font |
105
+ | `misleading-wording` | Warning/Critical | Ambiguous labels ("OK", "Continue"…) |
106
+ | `missing-info` | Warning | Mandatory information absent from the text |
107
+
108
+ ## Automatically recognised CMPs
109
+
110
+ Axeptio, Cookiebot, OneTrust, Didomi, Tarteaucitron, Usercentrics, and about twenty others via their specific CSS selectors. A heuristic fallback (fixed/sticky element with cookie-related text) covers custom banners.
111
+
112
+ ## Development
113
+
114
+ ```bash
115
+ pnpm dev # Watch-mode compilation
116
+ pnpm typecheck # Type-check without compiling
117
+ pnpm lint # oxlint
118
+ pnpm format # oxfmt
119
+ ```
120
+
121
+ ## Release
122
+
123
+ Releases are published automatically to [npm](https://www.npmjs.com/package/@slashgear/gdpr-cookie-scanner) and [GitHub Packages](https://github.com/Slashgear/gdpr-report/pkgs/npm/gdpr-cookie-scanner) via [Changesets](https://github.com/changesets/changesets). See [CONTRIBUTING.md](CONTRIBUTING.md) for the release process.
124
+
125
+ ## Contributing
126
+
127
+ See [CONTRIBUTING.md](CONTRIBUTING.md). This project follows the [Contributor Covenant](CODE_OF_CONDUCT.md) code of conduct.
package/SECURITY.md ADDED
@@ -0,0 +1,15 @@
1
+ # Security Policy
2
+
3
+ ## Reporting a vulnerability
4
+
5
+ If you discover a security vulnerability, **do not open a public issue**.
6
+
7
+ Send a report via [GitHub Security Advisories](https://github.com/Slashgear/gdpr-report/security/advisories/new) including:
8
+
9
+ - A description of the vulnerability
10
+ - Steps to reproduce it
11
+ - The potential impact
12
+
13
+ ## Scope
14
+
15
+ This tool runs a controlled Chromium browser against URLs provided by the user. It is designed to be run locally or in a controlled CI environment — do not expose the CLI as a web service without appropriate isolation.
@@ -0,0 +1,13 @@
1
+ import type { ComplianceScore, ConsentModal, ScannedCookie, NetworkRequest } from "../types.js";
2
+ interface ComplianceInput {
3
+ modal: ConsentModal;
4
+ cookiesBeforeInteraction: ScannedCookie[];
5
+ cookiesAfterAccept: ScannedCookie[];
6
+ cookiesAfterReject: ScannedCookie[];
7
+ networkBeforeInteraction: NetworkRequest[];
8
+ networkAfterAccept: NetworkRequest[];
9
+ networkAfterReject: NetworkRequest[];
10
+ }
11
+ export declare function analyzeCompliance(input: ComplianceInput): ComplianceScore;
12
+ export {};
13
+ //# sourceMappingURL=compliance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compliance.d.ts","sourceRoot":"","sources":["../../src/analyzers/compliance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EAEZ,aAAa,EACb,cAAc,EACf,MAAM,aAAa,CAAC;AAGrB,UAAU,eAAe;IACvB,KAAK,EAAE,YAAY,CAAC;IACpB,wBAAwB,EAAE,aAAa,EAAE,CAAC;IAC1C,kBAAkB,EAAE,aAAa,EAAE,CAAC;IACpC,kBAAkB,EAAE,aAAa,EAAE,CAAC;IACpC,wBAAwB,EAAE,cAAc,EAAE,CAAC;IAC3C,kBAAkB,EAAE,cAAc,EAAE,CAAC;IACrC,kBAAkB,EAAE,cAAc,EAAE,CAAC;CACtC;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,eAAe,GAAG,eAAe,CA+KzE"}