48tests
47passing
1known limitation
18numbered checks
Every line the script prints starts with a check number, such as FAIL [01] libbrotli1. Each test lists the lines a check must print.
Checks against tests
Rows are checks and columns are tests. A dot means the test asserts a line from that check.
Asserted, passing
Asserted, known limitation
Asserted, failing
Every run: the exit code matches the summary
| Check | 01–19 OS packages | 20–39 Runtimes | 40–59 Packages and files | 60–79 Container probe | 80–99 Script behaviour | |||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 60 | 61 | 62 | 63 | 64 | 65 | 80 | 81 | 82 | 83 | 84 | 85 | |
| [00]Header | ||||||||||||||||||||||||||||||||||||||||||||||||
| [01]OS packages | ||||||||||||||||||||||||||||||||||||||||||||||||
| [02]node and bun on PATH | ||||||||||||||||||||||||||||||||||||||||||||||||
| [03]Node.js version managers | ||||||||||||||||||||||||||||||||||||||||||||||||
| [04].NET runtimes | ||||||||||||||||||||||||||||||||||||||||||||||||
| [05]Python metadata | ||||||||||||||||||||||||||||||||||||||||||||||||
| [06]Python compiled extensions | ||||||||||||||||||||||||||||||||||||||||||||||||
| [07]Python pins and locks | ||||||||||||||||||||||||||||||||||||||||||||||||
| [08]Host Python packages | ||||||||||||||||||||||||||||||||||||||||||||||||
| [09]npm middleware | ||||||||||||||||||||||||||||||||||||||||||||||||
| [10]Java brotli4j | ||||||||||||||||||||||||||||||||||||||||||||||||
| [11]Ruby brotli gem | ||||||||||||||||||||||||||||||||||||||||||||||||
| [12]Go modules | ||||||||||||||||||||||||||||||||||||||||||||||||
| [13]Rust crates | ||||||||||||||||||||||||||||||||||||||||||||||||
| [14]Vendored decode.c | ||||||||||||||||||||||||||||||||||||||||||||||||
| [15]Bundled libbrotlidec | ||||||||||||||||||||||||||||||||||||||||||||||||
| [16]curl | ||||||||||||||||||||||||||||||||||||||||||||||||
| [17]Envoy, Istio, nginx | ||||||||||||||||||||||||||||||||||||||||||||||||
| [18]Container engine and images | ||||||||||||||||||||||||||||||||||||||||||||||||
Tests
| Test | Setup | Expected | Checks | Result |
|---|---|---|---|---|
| 01–19 · OS packages | ||||
| 01 | Debian 12, libbrotli1 1.0.9-2+b6 | FAIL | [01] | Pass |
| 02 | Debian 12, libbrotli1 1.0.9-2+deb12u1 | PASS | [01] | Pass |
| 03 | Ubuntu 22.04, libbrotli1 1.0.9-2build6 | FAIL | [01] | Pass |
| 04 | Alpine 3.20, brotli-libs 1.1.0-r2 (no 3.20 fix) | FAIL | [01] | Pass |
| 05 | Ubuntu 22.04, libbrotli1 1.0.9-2ubuntu0.1 and curl | PASS for both | [01] [16] | Pass |
| 06 | Ubuntu 20.04, 1.0.7-6ubuntu0.1 and the Pro build +esm1 | FAIL, then PASS | [01] | Pass |
| 07 | Sid fix, forky build, a binNMU of the fix, a ~rc1 prerelease | PASS, FAIL, not FAIL, WARN | [01] | Pass |
| 08 | Fedora 44, brotli 1.2.0-3.fc44 | WARN, never PASS | [01] | Pass |
| 09 | Ubuntu 24.04, libbrotli1 1.1.0-2build2 | FAIL | [01] | Pass |
| 10 | Ubuntu 26.04, libbrotli1 1.2.0-3ubuntu0.1 | PASS | [01] | Pass |
| 11 | Debian 13, libbrotli1 1.1.0-2+b7 | FAIL | [01] | Pass |
| 12 | Alpine 3.21, brotli-libs 1.1.1-r0 | PASS | [01] | Pass |
| 13 | Homebrew listing brotli 1.1.0_1 and 1.2.1 | FAIL, then PASS | [01] | Pass |
| 20–39 · Runtimes | ||||
| 20 | Official Node 24.22.0, plus 24.22.1 under nvm | FAIL, then PASS by marker | [02] [03] | Pass |
| 21 | Official Node 24.22.1 and an Express 5 app | PASS by marker | [02] [09] | Pass |
| 22 | nvm, Volta, asdf and fnm dirs either side of each fix | FAIL or PASS per branch | [03] | Pass |
| 23 | Debian nodejs and curl on the fixed system library | PASS through check 01 | [02] [16] | Pass |
| 24 | Microsoft .NET runtime 8.0.32 image | FAIL | [04] | Pass |
| 25 | Microsoft .NET runtime 8.0.33 image | PASS | [04] | Pass |
| 26 | dotnet --list-runtimes with 8.0.32, 7.0.20, 11.0.0-rc.2, 10.0.14 | FAIL, FAIL, WARN, PASS | [04] | Pass |
| 27 | Official Bun 1.4.3 | FAIL | [02] | Pass |
| 28 | Official Bun 1.4.4 | PASS by marker | [02] | Pass |
| 29 | Envoy 1.39.2 with a Brotli decompressor in its config | WARN | [17] | Pass |
| 30 | istioctl 1.31.1 version output | WARN | [17] | Pass |
| 31 | Test 01 plus curl | FAIL | [01] [16] | Pass |
| 40–59 · Packages and files | ||||
| 40 | Express 5 lockfile, Brotli 1.1.0 and 1.2.1 dist-info | FAIL, PASS, WARN | [05] [09] | Pass |
| 41 | Real Brotli, brotlicffi and curl_cffi wheels in two venvs | FAIL and PASS per venv | [05] [06] [08] | Pass |
| 42 | Requirement-line variants, poetry.lock, uv.lock, look-alike names | One verdict per real pin | [07] | Pass |
| 43 | yarn with @types/express@5, pnpm v9, bun.lock | No false Express 5 | [09] | Pass |
| 44 | Java, Ruby, Go and Rust either side of each fix, path with a space | FAIL or PASS per file | [10] [11] [12] [13] | Pass |
| 45 | Go pseudo-version and -rc.1 before v1.2.7 | WARN, never PASS | [12] | Pass |
| 46 | Upstream decode.c from v1.0.9, v1.0.10, v1.2.0, v1.2.1 | FAIL or PASS per tag | [14] | Pass |
| 47 | libbrotlidec built from upstream v1.0.9 to v1.1.1 | PASS fixed, WARN vulnerable | [15] | Pass |
| 48 | Debian python3-brotli 1.0.9-2+b6 | FAIL | [01] [06] [08] | Pass |
| 49 | dist-info from conda, no installer, a .post1 release | WARN where unsure | [05] | Pass |
| 50 | CRLF Gemfile.lock, pdm.lock, package-lock v1, nested Express, egg-info | A line for each, none PASS | [03] [05] [07] [09] [11] | Pass |
| 60–79 · Container probe | ||||
| 60 | Probe of test 01's image | FAIL | [18] | Pass |
| 61 | Probe of a distroless Node image (no shell) | SKIP | [18] | Pass |
| 62 | Probe of test 41's image | FAIL for system and venv packages | [18] | Known limitation |
| 63 | Probe of test 20's image | FAIL | [18] | Pass |
| 64 | Probe of official Node 24.22.1 on Alpine | PASS by marker | [18] | Pass |
| 65 | Probe of a vulnerable and a fixed image in one run | FAIL, then PASS | [18] | Pass |
| 80–99 · Script behaviour | ||||
| 80 | Bash 3.2 (the macOS version) on BusyBox | Same verdicts as bash 5 | [07] [11] [12] [14] | Pass |
| 81 | A WARN-only run with --strict | Exit 1 | [12] | Pass |
| 82 | Test 01's image with -q | FAIL lines and summary only | [01] | Pass |
| 83 | -i naming an image that doesn't exist | Exit 2 | [18] | Pass |
| 84 | Vulnerable files in an unreadable directory | Nothing PASSes | [12] | Pass |
| 85 | Docker hangs, Podman errors, -c | SKIP, no hang | [18] | Pass |
How the tests run
- Each test runs in a container with no network access, with the script mounted read-only.
- Package and binary checks use the real package, pinned to an exact version.
- Lockfile and source checks use sample files.
- Expected results come from vendor advisories, distro security trackers and OSV, never from the script's own output.
Known limitations
- In
-cmode the script doesn't look inside an image's virtualenvs,node_modulesor bundled libraries (test 62). - Distros other than Debian, Ubuntu and Alpine get WARN, because their patched builds keep the upstream version number.
- macOS-only checks (Homebrew,
otool) can't run in a Linux container, so the tests don't cover them.