@slashgear/gdpr-cookie-scanner 3.1.0 → 3.2.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.
- package/CHANGELOG.md +17 -0
- package/README.md +85 -9
- package/dist/cli.js +21 -1
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/src/cli.ts +37 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @slashgear/gdpr-cookie-scanner
|
|
2
2
|
|
|
3
|
+
## 3.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 51e7d6a: Add `--fail-on` option to the `scan` command to exit with code 1 when the compliance score falls below a specified threshold.
|
|
8
|
+
|
|
9
|
+
The threshold can be expressed as a **letter grade** (`A`, `B`, `C`, `D`, `F`) or a **numeric score** (`0–100`). Defaults to `F` (preserves existing behaviour).
|
|
10
|
+
|
|
11
|
+
Examples:
|
|
12
|
+
|
|
13
|
+
- `--fail-on B` — fail if the site scores below B (i.e. grade C, D, or F)
|
|
14
|
+
- `--fail-on 70` — fail if the total score is below 70/100
|
|
15
|
+
|
|
16
|
+
Useful for CI pipelines where you want to enforce a minimum compliance level.
|
|
17
|
+
|
|
18
|
+
The README now includes ready-to-use examples for **GitHub Actions** and **GitLab CI** using the Docker image.
|
|
19
|
+
|
|
3
20
|
## 3.1.0
|
|
4
21
|
|
|
5
22
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -57,14 +57,15 @@ gdpr-scan scan <url> [options]
|
|
|
57
57
|
|
|
58
58
|
### Options
|
|
59
59
|
|
|
60
|
-
| Option | Default | Description
|
|
61
|
-
| ------------------------ | ---------------- |
|
|
62
|
-
| `-o, --output <dir>` | `./gdpr-reports` | Output directory for the report
|
|
63
|
-
| `-t, --timeout <ms>` | `30000` | Navigation timeout
|
|
64
|
-
| `-f, --format <formats>` | `html` | Output formats: `md`, `html`, `json`, `pdf` (comma-separated)
|
|
65
|
-
| `--
|
|
66
|
-
|
|
|
67
|
-
| `-
|
|
60
|
+
| Option | Default | Description |
|
|
61
|
+
| ------------------------ | ---------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
62
|
+
| `-o, --output <dir>` | `./gdpr-reports` | Output directory for the report |
|
|
63
|
+
| `-t, --timeout <ms>` | `30000` | Navigation timeout |
|
|
64
|
+
| `-f, --format <formats>` | `html` | Output formats: `md`, `html`, `json`, `pdf` (comma-separated) |
|
|
65
|
+
| `--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`) |
|
|
66
|
+
| `--no-screenshots` | — | Disable screenshot capture |
|
|
67
|
+
| `-l, --locale <locale>` | `fr-FR` | Browser locale |
|
|
68
|
+
| `-v, --verbose` | — | Show full stack trace on error |
|
|
68
69
|
|
|
69
70
|
### Examples
|
|
70
71
|
|
|
@@ -84,10 +85,85 @@ gdpr-scan scan https://example.com -f md
|
|
|
84
85
|
# Generate all formats at once
|
|
85
86
|
gdpr-scan scan https://example.com -f md,html,json,pdf
|
|
86
87
|
|
|
88
|
+
# Fail (exit 1) if the site is graded below B — useful in CI
|
|
89
|
+
gdpr-scan scan https://example.com --fail-on B
|
|
90
|
+
|
|
91
|
+
# Fail if the numeric score is below 70/100
|
|
92
|
+
gdpr-scan scan https://example.com --fail-on 70
|
|
93
|
+
|
|
87
94
|
# Show the built-in tracker database
|
|
88
95
|
gdpr-scan list-trackers
|
|
89
96
|
```
|
|
90
97
|
|
|
98
|
+
## CI integration
|
|
99
|
+
|
|
100
|
+
Use `--fail-on` to gate a pipeline on compliance: the process exits with code `1` when the threshold is not met, causing the job to fail.
|
|
101
|
+
|
|
102
|
+
### GitHub Actions
|
|
103
|
+
|
|
104
|
+
```yaml
|
|
105
|
+
# .github/workflows/gdpr.yml
|
|
106
|
+
name: GDPR compliance
|
|
107
|
+
|
|
108
|
+
on:
|
|
109
|
+
schedule:
|
|
110
|
+
- cron: "0 6 * * 1" # every Monday at 06:00 UTC
|
|
111
|
+
workflow_dispatch:
|
|
112
|
+
|
|
113
|
+
jobs:
|
|
114
|
+
scan:
|
|
115
|
+
runs-on: ubuntu-latest
|
|
116
|
+
container:
|
|
117
|
+
image: ghcr.io/slashgear/gdpr-cookie-scanner:latest
|
|
118
|
+
steps:
|
|
119
|
+
- name: Scan
|
|
120
|
+
run: |
|
|
121
|
+
gdpr-scan scan https://example.com \
|
|
122
|
+
--fail-on B \
|
|
123
|
+
--format json,html \
|
|
124
|
+
-o /tmp/reports
|
|
125
|
+
|
|
126
|
+
- name: Upload report
|
|
127
|
+
if: always() # keep the report even when the scan fails
|
|
128
|
+
uses: actions/upload-artifact@v4
|
|
129
|
+
with:
|
|
130
|
+
name: gdpr-report
|
|
131
|
+
path: /tmp/reports/
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
> [!TIP]
|
|
135
|
+
> Using `if: always()` on the upload step ensures the report is available even when the job fails due to `--fail-on`.
|
|
136
|
+
|
|
137
|
+
### GitLab CI
|
|
138
|
+
|
|
139
|
+
```yaml
|
|
140
|
+
# .gitlab-ci.yml
|
|
141
|
+
gdpr-scan:
|
|
142
|
+
image: ghcr.io/slashgear/gdpr-cookie-scanner:latest
|
|
143
|
+
stage: test
|
|
144
|
+
script:
|
|
145
|
+
- gdpr-scan scan https://example.com --fail-on B --format json,html -o reports
|
|
146
|
+
artifacts:
|
|
147
|
+
when: always # keep report on failure too
|
|
148
|
+
paths:
|
|
149
|
+
- reports/
|
|
150
|
+
expire_in: 30 days
|
|
151
|
+
rules:
|
|
152
|
+
- if: $CI_PIPELINE_SOURCE == "schedule"
|
|
153
|
+
- if: $CI_PIPELINE_SOURCE == "web"
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Threshold reference
|
|
157
|
+
|
|
158
|
+
| `--fail-on` value | Fails when grade is… | Fails when score is… |
|
|
159
|
+
| ----------------- | -------------------- | -------------------- |
|
|
160
|
+
| `A` | B, C, D, or F | < 90 |
|
|
161
|
+
| `B` | C, D, or F | < 75 |
|
|
162
|
+
| `C` | D or F | < 55 |
|
|
163
|
+
| `D` | F | < 35 |
|
|
164
|
+
| `F` _(default)_ | F only | < 35 |
|
|
165
|
+
| `70` _(number)_ | any grade | < 70 |
|
|
166
|
+
|
|
91
167
|
## Programmatic API
|
|
92
168
|
|
|
93
169
|
The package can be used as a Node.js library — no CLI required.
|
|
@@ -204,7 +280,7 @@ The score is made up of 4 criteria (25 points each):
|
|
|
204
280
|
|
|
205
281
|
**Grade scale:** A ≥ 90 · B ≥ 75 · C ≥ 55 · D ≥ 35 · F < 35
|
|
206
282
|
|
|
207
|
-
|
|
283
|
+
**Exit codes:** `0` success · `1` threshold not met (see `--fail-on`) · `2` scan error
|
|
208
284
|
|
|
209
285
|
## Detected dark patterns
|
|
210
286
|
|
package/dist/cli.js
CHANGED
|
@@ -20,6 +20,7 @@ program
|
|
|
20
20
|
.option("-l, --locale <locale>", "Browser locale for language detection", "fr-FR")
|
|
21
21
|
.option("-v, --verbose", "Show detailed output", false)
|
|
22
22
|
.option("-f, --format <formats>", "Output formats: md, html, json, pdf (comma-separated)", "html")
|
|
23
|
+
.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")
|
|
23
24
|
.action(async (url, opts) => {
|
|
24
25
|
console.log();
|
|
25
26
|
console.log(styleText(["bold", "blue"], " GDPR Cookie Scanner"));
|
|
@@ -82,7 +83,13 @@ program
|
|
|
82
83
|
console.log(styleText("green", ` ${(labels[fmt] ?? fmt).padEnd(8)} ${path}`));
|
|
83
84
|
}
|
|
84
85
|
console.log();
|
|
85
|
-
|
|
86
|
+
const threshold = opts.failOn;
|
|
87
|
+
const failed = isBeforeThreshold(result.compliance.total, result.compliance.grade, threshold);
|
|
88
|
+
if (failed) {
|
|
89
|
+
console.log(styleText("red", ` Failed threshold: score ${result.compliance.total}/100 (grade ${result.compliance.grade}) is below --fail-on ${threshold.toUpperCase()}`));
|
|
90
|
+
console.log();
|
|
91
|
+
}
|
|
92
|
+
process.exit(failed ? 1 : 0);
|
|
86
93
|
}
|
|
87
94
|
catch (err) {
|
|
88
95
|
spinner.error({ text: "Scan failed" });
|
|
@@ -116,6 +123,19 @@ function normalizeUrl(url) {
|
|
|
116
123
|
}
|
|
117
124
|
return url;
|
|
118
125
|
}
|
|
126
|
+
const GRADE_ORDER = { A: 4, B: 3, C: 2, D: 1, F: 0 };
|
|
127
|
+
function isBeforeThreshold(score, grade, threshold) {
|
|
128
|
+
const asNumber = Number(threshold);
|
|
129
|
+
if (!Number.isNaN(asNumber)) {
|
|
130
|
+
return score < asNumber;
|
|
131
|
+
}
|
|
132
|
+
const upper = threshold.toUpperCase();
|
|
133
|
+
if (!(upper in GRADE_ORDER)) {
|
|
134
|
+
console.error(styleText("red", ` Invalid --fail-on value "${threshold}". Use a grade (A/B/C/D/F) or a number (0-100).`));
|
|
135
|
+
process.exit(2);
|
|
136
|
+
}
|
|
137
|
+
return (GRADE_ORDER[grade] ?? 0) < GRADE_ORDER[upper];
|
|
138
|
+
}
|
|
119
139
|
function formatScore(score) {
|
|
120
140
|
const colored = score >= 80
|
|
121
141
|
? styleText("green", String(score))
|
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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"}
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -24,6 +24,11 @@ program
|
|
|
24
24
|
.option("-l, --locale <locale>", "Browser locale for language detection", "fr-FR")
|
|
25
25
|
.option("-v, --verbose", "Show detailed output", false)
|
|
26
26
|
.option("-f, --format <formats>", "Output formats: md, html, json, pdf (comma-separated)", "html")
|
|
27
|
+
.option(
|
|
28
|
+
"--fail-on <threshold>",
|
|
29
|
+
"Exit with code 1 if grade is below this letter (A/B/C/D/F) or score is below this number",
|
|
30
|
+
"F",
|
|
31
|
+
)
|
|
27
32
|
.action(async (url: string, opts) => {
|
|
28
33
|
console.log();
|
|
29
34
|
console.log(styleText(["bold", "blue"], " GDPR Cookie Scanner"));
|
|
@@ -112,7 +117,18 @@ program
|
|
|
112
117
|
}
|
|
113
118
|
console.log();
|
|
114
119
|
|
|
115
|
-
|
|
120
|
+
const threshold = opts.failOn as string;
|
|
121
|
+
const failed = isBeforeThreshold(result.compliance.total, result.compliance.grade, threshold);
|
|
122
|
+
if (failed) {
|
|
123
|
+
console.log(
|
|
124
|
+
styleText(
|
|
125
|
+
"red",
|
|
126
|
+
` Failed threshold: score ${result.compliance.total}/100 (grade ${result.compliance.grade}) is below --fail-on ${threshold.toUpperCase()}`,
|
|
127
|
+
),
|
|
128
|
+
);
|
|
129
|
+
console.log();
|
|
130
|
+
}
|
|
131
|
+
process.exit(failed ? 1 : 0);
|
|
116
132
|
} catch (err) {
|
|
117
133
|
spinner.error({ text: "Scan failed" });
|
|
118
134
|
console.error(
|
|
@@ -151,6 +167,26 @@ function normalizeUrl(url: string): string {
|
|
|
151
167
|
return url;
|
|
152
168
|
}
|
|
153
169
|
|
|
170
|
+
const GRADE_ORDER: Record<string, number> = { A: 4, B: 3, C: 2, D: 1, F: 0 };
|
|
171
|
+
|
|
172
|
+
function isBeforeThreshold(score: number, grade: string, threshold: string): boolean {
|
|
173
|
+
const asNumber = Number(threshold);
|
|
174
|
+
if (!Number.isNaN(asNumber)) {
|
|
175
|
+
return score < asNumber;
|
|
176
|
+
}
|
|
177
|
+
const upper = threshold.toUpperCase();
|
|
178
|
+
if (!(upper in GRADE_ORDER)) {
|
|
179
|
+
console.error(
|
|
180
|
+
styleText(
|
|
181
|
+
"red",
|
|
182
|
+
` Invalid --fail-on value "${threshold}". Use a grade (A/B/C/D/F) or a number (0-100).`,
|
|
183
|
+
),
|
|
184
|
+
);
|
|
185
|
+
process.exit(2);
|
|
186
|
+
}
|
|
187
|
+
return (GRADE_ORDER[grade] ?? 0) < GRADE_ORDER[upper];
|
|
188
|
+
}
|
|
189
|
+
|
|
154
190
|
function formatScore(score: number): string {
|
|
155
191
|
const colored =
|
|
156
192
|
score >= 80
|