bfsg-scanner 0.2.1 → 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/CHANGELOG.md +21 -1
- package/README.md +5 -3
- package/dist/cli/run.d.ts +8 -0
- package/dist/cli/run.js +18 -0
- package/dist/cli/run.js.map +1 -1
- package/dist/discovery/discover.d.ts +4 -3
- package/dist/discovery/discover.js +10 -6
- package/dist/discovery/discover.js.map +1 -1
- package/docs/adr/0011-exit-code-for-unexpected-errors.md +48 -0
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,25 @@ follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.2.2] - 2026-09-29
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- A sub-sitemap that answers `200` with something other than a sitemap (a
|
|
14
|
+
soft-404 HTML page, a truncated file) is now skipped like an unreachable
|
|
15
|
+
one. Previously it discarded the whole sitemap and fell back to crawling.
|
|
16
|
+
- A root sitemap that is not well-formed XML now falls back to crawling
|
|
17
|
+
instead of aborting the run.
|
|
18
|
+
- An unexpected failure (Chromium not installed, an unwritable output
|
|
19
|
+
directory) now prints a one-line message and exits `4`. Previously it
|
|
20
|
+
crashed with a stack trace and exit code `1`, the code reserved for
|
|
21
|
+
"violations found". See ADR 0011.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- Dependency bump: `yaml` 2.9.0 → 2.9.1, `zod` 4.6.2 → 4.6.5. No behavior
|
|
26
|
+
change.
|
|
27
|
+
|
|
9
28
|
## [0.2.1] - 2026-09-14
|
|
10
29
|
|
|
11
30
|
### Changed
|
|
@@ -58,7 +77,8 @@ First release.
|
|
|
58
77
|
- Distributable package: a `bfsg-scanner` bin and a `dist` build that
|
|
59
78
|
excludes tests.
|
|
60
79
|
|
|
61
|
-
[Unreleased]: https://github.com/MihaelaAghirculesei/bfsg-scanner/compare/v0.2.
|
|
80
|
+
[Unreleased]: https://github.com/MihaelaAghirculesei/bfsg-scanner/compare/v0.2.2...HEAD
|
|
81
|
+
[0.2.2]: https://github.com/MihaelaAghirculesei/bfsg-scanner/compare/v0.2.1...v0.2.2
|
|
62
82
|
[0.2.1]: https://github.com/MihaelaAghirculesei/bfsg-scanner/compare/v0.2.0...v0.2.1
|
|
63
83
|
[0.2.0]: https://github.com/MihaelaAghirculesei/bfsg-scanner/compare/v0.1.0...v0.2.0
|
|
64
84
|
[0.1.0]: https://github.com/MihaelaAghirculesei/bfsg-scanner/releases/tag/v0.1.0
|
package/README.md
CHANGED
|
@@ -177,9 +177,11 @@ The terminal prints a summary and the distinct breached clauses.
|
|
|
177
177
|
| `1` | Scan completed; violations at or above `--fail-on`. |
|
|
178
178
|
| `2` | Invalid arguments or configuration. |
|
|
179
179
|
| `3` | No pages discovered, or a page could not be scanned. |
|
|
180
|
+
| `4` | Unexpected error — e.g. Chromium not installed, output directory not writable. |
|
|
180
181
|
|
|
181
182
|
`3` outranks `1`: a run with unreachable pages scanned an incomplete site, so
|
|
182
|
-
"no violations found" would be a claim the data cannot support.
|
|
183
|
+
"no violations found" would be a claim the data cannot support. `4` means
|
|
184
|
+
the run itself broke, not the site: fix the environment and run again.
|
|
183
185
|
|
|
184
186
|
## Use in CI
|
|
185
187
|
|
|
@@ -187,13 +189,13 @@ The non-zero exit at or above `--fail-on` lets a CI job block a merge on
|
|
|
187
189
|
accessibility. A GitHub Actions step:
|
|
188
190
|
|
|
189
191
|
```yaml
|
|
190
|
-
- uses: actions/setup-node@
|
|
192
|
+
- uses: actions/setup-node@v7
|
|
191
193
|
with:
|
|
192
194
|
node-version: 22
|
|
193
195
|
- run: npx playwright install --with-deps chromium
|
|
194
196
|
- run: npx bfsg-scanner https://staging.example.de --fail-on serious
|
|
195
197
|
- if: always()
|
|
196
|
-
uses: actions/upload-artifact@
|
|
198
|
+
uses: actions/upload-artifact@v7
|
|
197
199
|
with:
|
|
198
200
|
name: accessibility-report
|
|
199
201
|
path: reports/
|
package/dist/cli/run.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ interface CliArgs {
|
|
|
18
18
|
* 1 - scan completed, violations at or above `failOn` were found
|
|
19
19
|
* 2 - invalid arguments or configuration
|
|
20
20
|
* 3 - no pages were discovered, or one or more pages could not be scanned
|
|
21
|
+
* 4 - unexpected error, see `run`
|
|
21
22
|
*
|
|
22
23
|
* 3 outranks 1: a run with unreachable pages scanned an incomplete site, so
|
|
23
24
|
* "no violations found" would be a claim the data cannot support. The
|
|
@@ -25,5 +26,12 @@ interface CliArgs {
|
|
|
25
26
|
* survive either way.
|
|
26
27
|
*/
|
|
27
28
|
export declare function parseCliArgs(argv: readonly string[]): CliArgs;
|
|
29
|
+
/**
|
|
30
|
+
* Anything that escapes the handled paths — Chromium not installed, an
|
|
31
|
+
* unwritable output directory — ends here as exit code 4. Left to crash, it
|
|
32
|
+
* would surface as Node's default exit code 1, which the contract reserves
|
|
33
|
+
* for "violations found": a CI log would read a broken runner as an
|
|
34
|
+
* inaccessible site.
|
|
35
|
+
*/
|
|
28
36
|
export declare function run(argv: readonly string[], deps?: ScanDeps): Promise<number>;
|
|
29
37
|
export {};
|
package/dist/cli/run.js
CHANGED
|
@@ -31,6 +31,7 @@ Exit codes:
|
|
|
31
31
|
1 scan completed, violations at or above fail-on
|
|
32
32
|
2 invalid arguments or configuration
|
|
33
33
|
3 no pages discovered, or a page could not be scanned
|
|
34
|
+
4 unexpected error (e.g. Chromium not installed, output not writable)
|
|
34
35
|
`;
|
|
35
36
|
const OPTIONS = {
|
|
36
37
|
help: { type: 'boolean', short: 'h' },
|
|
@@ -56,6 +57,7 @@ function safeParseArgs(argv) {
|
|
|
56
57
|
* 1 - scan completed, violations at or above `failOn` were found
|
|
57
58
|
* 2 - invalid arguments or configuration
|
|
58
59
|
* 3 - no pages were discovered, or one or more pages could not be scanned
|
|
60
|
+
* 4 - unexpected error, see `run`
|
|
59
61
|
*
|
|
60
62
|
* 3 outranks 1: a run with unreachable pages scanned an incomplete site, so
|
|
61
63
|
* "no violations found" would be a claim the data cannot support. The
|
|
@@ -111,7 +113,23 @@ function resolveConfig(cli) {
|
|
|
111
113
|
}
|
|
112
114
|
return parseConfig({ ...fromFile, ...cli.overrides }, 'command-line arguments');
|
|
113
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* Anything that escapes the handled paths — Chromium not installed, an
|
|
118
|
+
* unwritable output directory — ends here as exit code 4. Left to crash, it
|
|
119
|
+
* would surface as Node's default exit code 1, which the contract reserves
|
|
120
|
+
* for "violations found": a CI log would read a broken runner as an
|
|
121
|
+
* inaccessible site.
|
|
122
|
+
*/
|
|
114
123
|
export async function run(argv, deps = {}) {
|
|
124
|
+
try {
|
|
125
|
+
return await runUnguarded(argv, deps);
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
console.error(`Unexpected error: ${error instanceof Error ? error.message : String(error)}`);
|
|
129
|
+
return 4;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async function runUnguarded(argv, deps) {
|
|
115
133
|
let cli;
|
|
116
134
|
try {
|
|
117
135
|
cli = parseCliArgs(argv);
|
package/dist/cli/run.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/cli/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAgB,QAAQ,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAe,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACvF,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,cAAc,EACd,WAAW,GACZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAiB,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,MAAM,mBAAmB,GAAG,kBAAkB,CAAC;AAE/C,MAAM,SAAS,GAAG;;;;;;;;;0DASwC,mBAAmB
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/cli/run.ts"],"names":[],"mappings":"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"}
|
|
@@ -18,8 +18,9 @@ export interface DiscoverFromSitemapOptions {
|
|
|
18
18
|
* crawlSite), duplicate URLs are collapsed, and discovery stops as soon as
|
|
19
19
|
* maxPages is reached.
|
|
20
20
|
*
|
|
21
|
-
* A failure to load the root sitemap is fatal
|
|
22
|
-
*
|
|
23
|
-
*
|
|
21
|
+
* A failure to load or parse the root sitemap is fatal and always surfaces
|
|
22
|
+
* as a SitemapError (the caller should fall back to crawling). A failure on
|
|
23
|
+
* a sub-sitemap referenced by an index is not: that one sub-sitemap is
|
|
24
|
+
* skipped and discovery continues with the rest.
|
|
24
25
|
*/
|
|
25
26
|
export declare function discoverFromSitemap(options: DiscoverFromSitemapOptions): Promise<string[]>;
|
|
@@ -9,9 +9,10 @@ import { parseSitemapXml, SitemapError } from './sitemap.js';
|
|
|
9
9
|
* crawlSite), duplicate URLs are collapsed, and discovery stops as soon as
|
|
10
10
|
* maxPages is reached.
|
|
11
11
|
*
|
|
12
|
-
* A failure to load the root sitemap is fatal
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* A failure to load or parse the root sitemap is fatal and always surfaces
|
|
13
|
+
* as a SitemapError (the caller should fall back to crawling). A failure on
|
|
14
|
+
* a sub-sitemap referenced by an index is not: that one sub-sitemap is
|
|
15
|
+
* skipped and discovery continues with the rest.
|
|
15
16
|
*/
|
|
16
17
|
export async function discoverFromSitemap(options) {
|
|
17
18
|
const { baseUrl, maxPages, sitemapPath = '/sitemap.xml', excludePaths = [], fetchFn = fetchWithUserAgent, maxSitemapDepth = 3, } = options;
|
|
@@ -30,13 +31,17 @@ export async function discoverFromSitemap(options) {
|
|
|
30
31
|
return;
|
|
31
32
|
}
|
|
32
33
|
visitedSitemaps.add(sitemapUrl);
|
|
33
|
-
|
|
34
|
+
// Parsing sits inside the same guard as the fetch: a URL that answers
|
|
35
|
+
// 200 with something other than a sitemap (a soft-404 HTML page, a
|
|
36
|
+
// truncated file) is as unusable as one that answers 404, and must be
|
|
37
|
+
// skipped the same way rather than abort the whole sitemap.
|
|
38
|
+
let doc;
|
|
34
39
|
try {
|
|
35
40
|
const response = await fetchFn(sitemapUrl);
|
|
36
41
|
if (!response.ok) {
|
|
37
42
|
throw new Error(`HTTP ${response.status}`);
|
|
38
43
|
}
|
|
39
|
-
|
|
44
|
+
doc = parseSitemapXml(await response.text());
|
|
40
45
|
}
|
|
41
46
|
catch (cause) {
|
|
42
47
|
if (depth === 0) {
|
|
@@ -44,7 +49,6 @@ export async function discoverFromSitemap(options) {
|
|
|
44
49
|
}
|
|
45
50
|
return;
|
|
46
51
|
}
|
|
47
|
-
const doc = parseSitemapXml(xml);
|
|
48
52
|
if (doc.kind === 'sitemapindex') {
|
|
49
53
|
for (const childUrl of doc.sitemaps) {
|
|
50
54
|
if (collected.length >= maxPages) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../../src/discovery/discover.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnE,OAAO,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../../src/discovery/discover.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnE,OAAO,EAAE,eAAe,EAAwB,YAAY,EAAE,MAAM,cAAc,CAAC;AAenF;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,OAAmC;IAC3E,MAAM,EACJ,OAAO,EACP,QAAQ,EACR,WAAW,GAAG,cAAc,EAC5B,YAAY,GAAG,EAAE,EACjB,OAAO,GAAG,kBAAkB,EAC5B,eAAe,GAAG,CAAC,GACpB,GAAG,OAAO,CAAC;IAEZ,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;IACvC,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC;IAEhE,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IACpC,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;IAE1C,MAAM,YAAY,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC;IAEtC,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAEpC,KAAK,UAAU,YAAY,CAAC,UAAkB,EAAE,KAAa;QAC3D,IAAI,SAAS,CAAC,MAAM,IAAI,QAAQ,EAAE,CAAC;YACjC,OAAO;QACT,CAAC;QACD,IAAI,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,KAAK,GAAG,eAAe,EAAE,CAAC;YAC/D,OAAO;QACT,CAAC;QACD,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAEhC,sEAAsE;QACtE,mEAAmE;QACnE,sEAAsE;QACtE,4DAA4D;QAC5D,IAAI,GAAoB,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;YAC3C,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CAAC,QAAQ,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;YAC7C,CAAC;YACD,GAAG,GAAG,eAAe,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;QAC/C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;gBAChB,MAAM,IAAI,YAAY,CACpB,2BAA2B,UAAU,MAAM,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACpG,CAAC;YACJ,CAAC;YACD,OAAO;QACT,CAAC;QAED,IAAI,GAAG,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YAChC,KAAK,MAAM,QAAQ,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;gBACpC,IAAI,SAAS,CAAC,MAAM,IAAI,QAAQ,EAAE,CAAC;oBACjC,OAAO;gBACT,CAAC;gBACD,MAAM,YAAY,CAAC,QAAQ,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;YAC1C,CAAC;YACD,OAAO;QACT,CAAC;QAED,KAAK,MAAM,OAAO,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;YAC/B,IAAI,SAAS,CAAC,MAAM,IAAI,QAAQ,EAAE,CAAC;gBACjC,OAAO;YACT,CAAC;YACD,IAAI,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC3B,SAAS;YACX,CAAC;YACD,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAEvB,IAAI,MAAW,CAAC;YAChB,IAAI,CAAC;gBACH,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;YAC5B,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YACD,IACE,MAAM,CAAC,MAAM,KAAK,MAAM;gBACxB,CAAC,cAAc,CAAC,MAAM,CAAC;gBACvB,qBAAqB,CAAC,MAAM,CAAC,QAAQ,EAAE,YAAY,CAAC,EACpD,CAAC;gBACD,SAAS;YACX,CAAC;YACD,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# 11. An exit code for unexpected errors
|
|
2
|
+
|
|
3
|
+
Date: 2026-09-29
|
|
4
|
+
|
|
5
|
+
## Status
|
|
6
|
+
|
|
7
|
+
Accepted. Extends the exit-code table of ADR 0003.
|
|
8
|
+
|
|
9
|
+
## Context
|
|
10
|
+
|
|
11
|
+
ADR 0003 defines `0` (pass), `1` (violations at or above `failOn`), `2`
|
|
12
|
+
(bad arguments or configuration) and `3` (incomplete scan). Every path that
|
|
13
|
+
`run` anticipates maps to one of them. A failure it does not anticipate —
|
|
14
|
+
Chromium missing on a first `npx` run, an output directory that cannot be
|
|
15
|
+
created — escaped as an unhandled rejection. Node then printed a stack
|
|
16
|
+
trace and exited `1`.
|
|
17
|
+
|
|
18
|
+
`1` is the one code a CI gate reads as a verdict on the site. A broken
|
|
19
|
+
runner therefore looked like an inaccessible site, and the person reading
|
|
20
|
+
the log went looking for violations that were never measured.
|
|
21
|
+
|
|
22
|
+
## Decision
|
|
23
|
+
|
|
24
|
+
`run` catches anything that escapes the handled paths, prints a one-line
|
|
25
|
+
`Unexpected error: <message>` to stderr, and returns **`4`**.
|
|
26
|
+
|
|
27
|
+
Alternatives considered:
|
|
28
|
+
|
|
29
|
+
- **Reuse `3`.** `3` already means "no trustworthy result". But it points
|
|
30
|
+
at the *site* (unreachable pages, nothing discoverable), and the fix is
|
|
31
|
+
on the site's side. A missing browser or a read-only disk is fixed on
|
|
32
|
+
the *runner's* side. Separate codes keep that distinction machine-readable.
|
|
33
|
+
- **Leave the crash, document it.** Cheapest, but the collision with `1`
|
|
34
|
+
is the defect being fixed; documenting it does not remove it.
|
|
35
|
+
|
|
36
|
+
The message is kept to the error's own text. Playwright's launch error
|
|
37
|
+
already names the `npx playwright install` command, so no hint is added
|
|
38
|
+
on top of it.
|
|
39
|
+
|
|
40
|
+
## Consequences
|
|
41
|
+
|
|
42
|
+
- The code is additive: a CI job that treats any non-zero code as failure
|
|
43
|
+
behaves as before; one that tests for `1` specifically no longer fires on
|
|
44
|
+
a broken runner.
|
|
45
|
+
- The stack trace is no longer printed. The message carries the cause;
|
|
46
|
+
a developer debugging the tool itself runs it from source.
|
|
47
|
+
- Any future failure mode that deserves its own code must be caught
|
|
48
|
+
explicitly before it reaches this net.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bfsg-scanner",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "WCAG 2.1 AA / BFSG compliance scanner built on Playwright and axe-core",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"accessibility",
|
|
@@ -58,16 +58,16 @@
|
|
|
58
58
|
"axe-core": "4.13.0",
|
|
59
59
|
"fast-xml-parser": "5.11.1",
|
|
60
60
|
"playwright": "1.63.0",
|
|
61
|
-
"yaml": "2.9.
|
|
62
|
-
"zod": "4.6.
|
|
61
|
+
"yaml": "2.9.1",
|
|
62
|
+
"zod": "4.6.5"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
|
-
"@biomejs/biome": "2.5.
|
|
66
|
-
"@types/node": "24.
|
|
65
|
+
"@biomejs/biome": "2.5.14",
|
|
66
|
+
"@types/node": "24.19.0",
|
|
67
67
|
"ajv": "8.20.0",
|
|
68
68
|
"rimraf": "6.1.3",
|
|
69
|
-
"tsx": "4.23.
|
|
69
|
+
"tsx": "4.23.15",
|
|
70
70
|
"typescript": "7.0.2",
|
|
71
|
-
"vitest": "
|
|
71
|
+
"vitest": "5.0.2"
|
|
72
72
|
}
|
|
73
73
|
}
|