cra24 1.0.0__tar.gz
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.
- cra24-1.0.0/.gitignore +40 -0
- cra24-1.0.0/CHANGELOG.md +283 -0
- cra24-1.0.0/CLA.md +182 -0
- cra24-1.0.0/LICENSE +235 -0
- cra24-1.0.0/LICENSING.md +76 -0
- cra24-1.0.0/NOTICE +61 -0
- cra24-1.0.0/PKG-INFO +332 -0
- cra24-1.0.0/README.md +291 -0
- cra24-1.0.0/docs/architecture.md +231 -0
- cra24-1.0.0/docs/article-14.md +228 -0
- cra24-1.0.0/docs/cli.md +380 -0
- cra24-1.0.0/docs/evidence.md +177 -0
- cra24-1.0.0/docs/feeds.md +207 -0
- cra24-1.0.0/docs/licensing-faq.md +206 -0
- cra24-1.0.0/docs/roadmap.md +184 -0
- cra24-1.0.0/docs/srp-field-spec.md +192 -0
- cra24-1.0.0/docs/triage-rules.md +262 -0
- cra24-1.0.0/docs/watch.md +225 -0
- cra24-1.0.0/pyproject.toml +107 -0
- cra24-1.0.0/src/cra24/__init__.py +25 -0
- cra24-1.0.0/src/cra24/__main__.py +10 -0
- cra24-1.0.0/src/cra24/cli.py +954 -0
- cra24-1.0.0/src/cra24/clock.py +328 -0
- cra24-1.0.0/src/cra24/config.py +172 -0
- cra24-1.0.0/src/cra24/data/annex.json +72 -0
- cra24-1.0.0/src/cra24/data/schemas/csaf_json_schema.json +1414 -0
- cra24-1.0.0/src/cra24/data/schemas/cvss-v2.0.json +8 -0
- cra24-1.0.0/src/cra24/data/schemas/cvss-v3.0.json +8 -0
- cra24-1.0.0/src/cra24/data/schemas/cvss-v3.1.json +60 -0
- cra24-1.0.0/src/cra24/data/schemas/openvex_json_schema.json +317 -0
- cra24-1.0.0/src/cra24/data/srp-fields.json +157 -0
- cra24-1.0.0/src/cra24/emit/__init__.py +28 -0
- cra24-1.0.0/src/cra24/emit/csaf.py +302 -0
- cra24-1.0.0/src/cra24/emit/srp.py +365 -0
- cra24-1.0.0/src/cra24/emit/validate.py +165 -0
- cra24-1.0.0/src/cra24/emit/vex.py +137 -0
- cra24-1.0.0/src/cra24/errors.py +61 -0
- cra24-1.0.0/src/cra24/evidence.py +367 -0
- cra24-1.0.0/src/cra24/feeds/__init__.py +40 -0
- cra24-1.0.0/src/cra24/feeds/base.py +389 -0
- cra24-1.0.0/src/cra24/feeds/cache.py +236 -0
- cra24-1.0.0/src/cra24/feeds/epss.py +104 -0
- cra24-1.0.0/src/cra24/feeds/euvd.py +177 -0
- cra24-1.0.0/src/cra24/feeds/kev.py +121 -0
- cra24-1.0.0/src/cra24/feeds/nvd.py +208 -0
- cra24-1.0.0/src/cra24/feeds/osv.py +242 -0
- cra24-1.0.0/src/cra24/feeds/registry.py +316 -0
- cra24-1.0.0/src/cra24/ingest/__init__.py +17 -0
- cra24-1.0.0/src/cra24/ingest/base.py +107 -0
- cra24-1.0.0/src/cra24/ingest/buildroot.py +180 -0
- cra24-1.0.0/src/cra24/ingest/sbom.py +181 -0
- cra24-1.0.0/src/cra24/ingest/yocto.py +305 -0
- cra24-1.0.0/src/cra24/logging.py +62 -0
- cra24-1.0.0/src/cra24/model.py +412 -0
- cra24-1.0.0/src/cra24/notify.py +310 -0
- cra24-1.0.0/src/cra24/purl.py +125 -0
- cra24-1.0.0/src/cra24/triage.py +651 -0
- cra24-1.0.0/src/cra24/versions.py +168 -0
- cra24-1.0.0/src/cra24/watch.py +338 -0
- cra24-1.0.0/tests/conftest.py +95 -0
- cra24-1.0.0/tests/fixtures/buildroot-output/build/linux-6.6.22/.config +17 -0
- cra24-1.0.0/tests/fixtures/buildroot-output/legal-info/manifest.csv +6 -0
- cra24-1.0.0/tests/fixtures/buildroot-output/pkg-stats.json +13 -0
- cra24-1.0.0/tests/fixtures/demo-config.json +16 -0
- cra24-1.0.0/tests/fixtures/feed-cache/epss/epss_scores-current.csv +6 -0
- cra24-1.0.0/tests/fixtures/feed-cache/epss/epss_scores-current.csv.meta +10 -0
- cra24-1.0.0/tests/fixtures/feed-cache/euvd/exploitedvulnerabilities.json +29 -0
- cra24-1.0.0/tests/fixtures/feed-cache/euvd/exploitedvulnerabilities.json.meta +10 -0
- cra24-1.0.0/tests/fixtures/feed-cache/kev/known_exploited_vulnerabilities.json +47 -0
- cra24-1.0.0/tests/fixtures/feed-cache/kev/known_exploited_vulnerabilities.json.meta +10 -0
- cra24-1.0.0/tests/fixtures/feed-cache/nvd/cves/CVE-2024-1086.json +58 -0
- cra24-1.0.0/tests/fixtures/feed-cache/nvd/cves/CVE-2024-1086.json.meta +10 -0
- cra24-1.0.0/tests/fixtures/feed-cache/osv/query/cd16302a59cc3cdb.json +42 -0
- cra24-1.0.0/tests/fixtures/feed-cache/osv/query/cd16302a59cc3cdb.json.meta +17 -0
- cra24-1.0.0/tests/fixtures/sbom-cyclonedx.json +32 -0
- cra24-1.0.0/tests/fixtures/sbom-spdx.json +23 -0
- cra24-1.0.0/tests/fixtures/yocto-build/tmp/deploy/images/raspberrypi4-64/config-6.6.22 +17 -0
- cra24-1.0.0/tests/fixtures/yocto-build/tmp/deploy/images/raspberrypi4-64/core-image-minimal.manifest +10 -0
- cra24-1.0.0/tests/fixtures/yocto-build/tmp/deploy/licenses/busybox/license.manifest +5 -0
- cra24-1.0.0/tests/fixtures/yocto-build/tmp/deploy/licenses/linux-raspberrypi/license.manifest +5 -0
- cra24-1.0.0/tests/fixtures/yocto-build/tmp/deploy/licenses/openssl/license.manifest +10 -0
- cra24-1.0.0/tests/fixtures/yocto-build/tmp/log/cve/cve-summary.json +72 -0
- cra24-1.0.0/tests/test_cli.py +558 -0
- cra24-1.0.0/tests/test_clock.py +135 -0
- cra24-1.0.0/tests/test_emit.py +275 -0
- cra24-1.0.0/tests/test_evidence.py +244 -0
- cra24-1.0.0/tests/test_feeds.py +362 -0
- cra24-1.0.0/tests/test_ingest.py +136 -0
- cra24-1.0.0/tests/test_model.py +142 -0
- cra24-1.0.0/tests/test_repo_hygiene.py +145 -0
- cra24-1.0.0/tests/test_triage.py +253 -0
- cra24-1.0.0/tests/test_versions.py +82 -0
- cra24-1.0.0/tests/test_watch.py +288 -0
cra24-1.0.0/.gitignore
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*.egg-info/
|
|
4
|
+
.eggs/
|
|
5
|
+
.venv/
|
|
6
|
+
venv/
|
|
7
|
+
.env
|
|
8
|
+
|
|
9
|
+
# Local working notes, scratch files and delivered artefacts. Anything in here
|
|
10
|
+
# is for this checkout only and must never reach a clone: keep working notes
|
|
11
|
+
# there rather than loose in the root, where they end up in a release tarball.
|
|
12
|
+
/__internal__/
|
|
13
|
+
|
|
14
|
+
# Anchored to the repository root on purpose. An unanchored `build/` also
|
|
15
|
+
# matches tests/fixtures/buildroot-output/build/, which silently excluded a
|
|
16
|
+
# kernel .config fixture and broke the suite only in a fresh clone.
|
|
17
|
+
/dist/
|
|
18
|
+
/build/
|
|
19
|
+
|
|
20
|
+
# pytest / tooling
|
|
21
|
+
.pytest_cache/
|
|
22
|
+
.ruff_cache/
|
|
23
|
+
.mypy_cache/
|
|
24
|
+
.coverage
|
|
25
|
+
coverage.xml
|
|
26
|
+
htmlcov/
|
|
27
|
+
|
|
28
|
+
# cra24 working output — never commit a customer's dossier. These contain an
|
|
29
|
+
# unpatched-vulnerability inventory of a shipping product.
|
|
30
|
+
/product.json
|
|
31
|
+
/dossier/
|
|
32
|
+
/evidence/
|
|
33
|
+
*.dossier/
|
|
34
|
+
.cra24-cache/
|
|
35
|
+
/watch-dossiers/
|
|
36
|
+
/products/
|
|
37
|
+
watch-state.json
|
|
38
|
+
|
|
39
|
+
# ...but the test fixtures are not working output.
|
|
40
|
+
!tests/fixtures/**
|
cra24-1.0.0/CHANGELOG.md
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
|
|
6
|
+
this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
Two kinds of change get called out specially, because they affect what you can
|
|
9
|
+
rely on:
|
|
10
|
+
|
|
11
|
+
- **Field spec** changes track the ENISA SRP form. They can alter which fields
|
|
12
|
+
block a submission, so they are listed even when no code changed.
|
|
13
|
+
- **Triage** changes can alter the verdict for a CVE you already published a VEX
|
|
14
|
+
statement about. Re-run and re-publish when you see one.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## [1.0.0] — 2026-09-19
|
|
19
|
+
|
|
20
|
+
First public release.
|
|
21
|
+
|
|
22
|
+
No functional change from 0.4.0. The version says 1.0 because the surface is
|
|
23
|
+
now one I am willing to keep stable: the CLI verbs and their exit codes, the
|
|
24
|
+
shape of `product.json`, and the emitted CSAF, OpenVEX and SRP documents. Those
|
|
25
|
+
are what a build pipeline and an auditor come to depend on, and breaking them
|
|
26
|
+
quietly is worse than a major version number.
|
|
27
|
+
|
|
28
|
+
Versions 0.1.0 through 0.4.0 were developed before publication and are not
|
|
29
|
+
tagged in this repository. The entries below are kept because they explain why
|
|
30
|
+
the engine behaves as it does — particularly which conclusions it refuses to
|
|
31
|
+
draw, and why.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## [0.4.0] — 2026-09-19
|
|
36
|
+
|
|
37
|
+
A correctness release. Nothing here is a new capability you asked for; it is
|
|
38
|
+
the set of things the engine was getting quietly wrong, found by reviewing it
|
|
39
|
+
against its own stated contracts.
|
|
40
|
+
|
|
41
|
+
### Triage
|
|
42
|
+
|
|
43
|
+
- **A kernel symbol that is merely *absent* no longer counts as "switched
|
|
44
|
+
off".** `read_kernel_config` has always recorded an explicitly unset symbol as
|
|
45
|
+
`n` so that "we looked and it is off" stays distinguishable from "we never
|
|
46
|
+
looked"; the config gate then collapsed the two. In a kconfig-generated
|
|
47
|
+
`.config` that was still right — every reachable symbol was considered when
|
|
48
|
+
the file was written — but `--kernel-config` also accepts a defconfig or a
|
|
49
|
+
`.cfg` fragment, which list only deltas. There, a gate symbol the file never
|
|
50
|
+
mentioned returned `not set in the shipped kernel config`, the verdict became
|
|
51
|
+
`not_affected`, and the CVE left the dossier on evidence the tool had never
|
|
52
|
+
actually checked.
|
|
53
|
+
|
|
54
|
+
Provenance now travels with the data: `product.json` records
|
|
55
|
+
`kernel_config_complete`, and the gate declines to conclude from absence
|
|
56
|
+
unless the config is complete.
|
|
57
|
+
|
|
58
|
+
**Re-run any dossier gated on a config fragment.** Verdicts produced from a
|
|
59
|
+
full `.config` are unchanged.
|
|
60
|
+
|
|
61
|
+
### Fixed
|
|
62
|
+
|
|
63
|
+
- **Article 14(4) is a calendar month, measured from the submission.** The
|
|
64
|
+
incident final-report deadline used `timedelta(days=30)` and counted from the
|
|
65
|
+
72-hour notification *deadline*. Regulation (EEC, Euratom) No 1182/71 counts
|
|
66
|
+
months to the day bearing the same number, and 14(4) runs from the submission:
|
|
67
|
+
a notification filed on 31 January is due 28 February, where the old
|
|
68
|
+
arithmetic said 2 March. Both errors moved the deadline later than the law
|
|
69
|
+
does. Where no submission time was recorded the 72-hour deadline is still
|
|
70
|
+
assumed, and the basis string now says so.
|
|
71
|
+
- **`cra24 doctor` no longer reports validation as available when it is not.**
|
|
72
|
+
It checked that `jsonschema` imported and nothing else, while the validator
|
|
73
|
+
also needs `referencing` and a `jsonschema` of at least 4.18. On a machine
|
|
74
|
+
with the distribution's jsonschema 4.10 and no `referencing` — Ubuntu 24.04,
|
|
75
|
+
for one — doctor printed a green line and the first `cra24 report` then died
|
|
76
|
+
with a bare `ModuleNotFoundError`. The check now covers what the validator
|
|
77
|
+
actually imports and names the missing piece.
|
|
78
|
+
- **Feed cache entry names are contained.** `root / feed / name` was built from
|
|
79
|
+
identifiers that arrive from outside — a CVE typed on the command line, but
|
|
80
|
+
also one read out of an SBOM or a cve-check summary — so an absolute name
|
|
81
|
+
replaced the path and `../` walked out of the cache directory.
|
|
82
|
+
- **Feed responses are bounded**, at 512 MiB before and after decompression. A
|
|
83
|
+
few hundred kilobytes of compressed zeros previously asked for as much memory
|
|
84
|
+
as it liked, on a watch that runs unattended on an hourly timer.
|
|
85
|
+
- **A redirect from `https` to plaintext `http` is refused** rather than
|
|
86
|
+
followed. The answers end up in a regulatory filing.
|
|
87
|
+
- A `429` or `5xx` on the final attempt no longer honours `Retry-After` before
|
|
88
|
+
giving up anyway.
|
|
89
|
+
|
|
90
|
+
### Added
|
|
91
|
+
|
|
92
|
+
- **`cra24 verify --expect-head SHA256`.** Deleting records from the end of the
|
|
93
|
+
ledger leaves a chain that is shorter and still internally consistent, so it
|
|
94
|
+
verified clean — nothing inside a ledger can detect its own truncation. The
|
|
95
|
+
head hash was always meant to be anchored somewhere you do not control; this
|
|
96
|
+
makes that anchor checkable.
|
|
97
|
+
- **`cra24 doctor` reports how the evidence key was read** — hex or text, and
|
|
98
|
+
how many bytes — in red below sixteen. A value that parses as hex is decoded
|
|
99
|
+
as hex, so the passphrase `deadbeef` is four bytes rather than eight. That
|
|
100
|
+
rule is unchanged, because changing it would invalidate every ledger already
|
|
101
|
+
signed under it.
|
|
102
|
+
- `tests/test_repo_hygiene.py`, which the `licence headers` CI job has invoked
|
|
103
|
+
since 0.2.0 without the file ever existing — so that job failed on every push
|
|
104
|
+
while the check it stood for was not running. Enforces the SPDX header and
|
|
105
|
+
copyright line on every source file, that each agrees with the licence
|
|
106
|
+
`pyproject.toml` declares, and that no workflow runs a test path that is not
|
|
107
|
+
there.
|
|
108
|
+
|
|
109
|
+
### Changed
|
|
110
|
+
|
|
111
|
+
- `Ledger.append()` reads the last record by seeking from the end instead of
|
|
112
|
+
parsing the whole ledger, so appending no longer costs the length of the
|
|
113
|
+
history. Ten years of hourly evidence was going to notice.
|
|
114
|
+
- `doctor`'s `jsonschema` line is now `validation`, since whether `jsonschema`
|
|
115
|
+
imports was never the thing it was reporting.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## [0.3.0] — 2026-09-18
|
|
120
|
+
|
|
121
|
+
The release that answers the hardest input: *is this actually being exploited?*
|
|
122
|
+
|
|
123
|
+
### Added
|
|
124
|
+
|
|
125
|
+
- **Five feed clients**, all offline-capable, all using `urllib` from the
|
|
126
|
+
standard library so the base package still has zero runtime dependencies.
|
|
127
|
+
|
|
128
|
+
| Feed | Answers |
|
|
129
|
+
| --- | --- |
|
|
130
|
+
| CISA KEV | is this actively exploited — the Article 14(1) trigger |
|
|
131
|
+
| ENISA EUVD | ENISA's own exploited list, plus the EUVD id for the SRP form |
|
|
132
|
+
| EPSS | how likely exploitation is in 30 days, for ordering the queue |
|
|
133
|
+
| OSV | which versions are affected and which one fixes it |
|
|
134
|
+
| NVD | CVSS score and vector for the notification and final report |
|
|
135
|
+
|
|
136
|
+
- **`cra24 feeds sync` and `cra24 feeds status`.** Status names every host that
|
|
137
|
+
would be contacted, how old each cached copy is, and — with `--terms` — the
|
|
138
|
+
terms of use, all without opening a socket.
|
|
139
|
+
- **An on-disk cache that is a feature, not an optimisation.** Payloads are
|
|
140
|
+
stored byte-identical to what the server sent, with the SHA-256 in a sidecar,
|
|
141
|
+
so a cached artefact can be hashed and shown to be the file CISA published. A
|
|
142
|
+
populated cache can be tarred up on a networked machine and copied to an
|
|
143
|
+
air-gapped build machine, which is the normal case in this industry.
|
|
144
|
+
- **`--offline` everywhere**, refusing to open a socket and saying how old the
|
|
145
|
+
cache is rather than pretending it is current.
|
|
146
|
+
- **`cra24 watch`** — poll the feeds against registered products and fire when
|
|
147
|
+
something lands. Writes the dossier and starts the clock at the moment of
|
|
148
|
+
detection, so what reaches you is a draft rather than an alert. Exits 1 on a
|
|
149
|
+
reportable finding.
|
|
150
|
+
- **Notifiers**: stdout, `file:`, `webhook:` and `email:`, repeatable. SMTP
|
|
151
|
+
credentials come from the environment, never a config file. A reportable alert
|
|
152
|
+
carries `X-CRA24-Reportable: yes`.
|
|
153
|
+
- **A hardened systemd unit and timer** in `contrib/systemd/` — a oneshot on a
|
|
154
|
+
timer rather than a long-lived daemon, with `RandomizedDelaySec` so that not
|
|
155
|
+
every installation polls CISA on the hour.
|
|
156
|
+
- `docs/feeds.md` and `docs/watch.md`.
|
|
157
|
+
|
|
158
|
+
### Changed
|
|
159
|
+
|
|
160
|
+
- `triage()` takes an optional `enrichment`. Feed data fills arguments the caller
|
|
161
|
+
did not supply and **never overrides one that was**: an explicit
|
|
162
|
+
`--actively-exploited no` is a human decision and a feed does not overturn it.
|
|
163
|
+
- Every fact a feed supplied appears in the evidence trail with the feed named,
|
|
164
|
+
so a dossier can show a verdict changed because CISA added the CVE this
|
|
165
|
+
morning rather than because the tool changed its mind.
|
|
166
|
+
- `cra24 doctor` reports which feeds are cached and whether `NVD_API_KEY` is set.
|
|
167
|
+
|
|
168
|
+
### Fixed
|
|
169
|
+
|
|
170
|
+
- An overdue obligation rendered as "7h 51m overdue left". `_fmt_delta` already
|
|
171
|
+
says "overdue"; the CLI no longer appends "left" to it. Nonsense wording at
|
|
172
|
+
exactly the moment someone is reading carefully.
|
|
173
|
+
|
|
174
|
+
### Triage
|
|
175
|
+
|
|
176
|
+
- **A CVE listed in CISA KEV or ENISA's exploited list is now reportable without
|
|
177
|
+
passing `--actively-exploited yes`.** Verdicts for such CVEs change from *not
|
|
178
|
+
reportable, exploitation unknown* to *reportable*. Re-run anything you assessed
|
|
179
|
+
before upgrading.
|
|
180
|
+
- **Absence from KEV is recorded as unknown, never as `False`.** KEV is
|
|
181
|
+
conservative, curated and US-federal; absence means CISA has not confirmed
|
|
182
|
+
exploitation, not that there is none. A customer reporting an attack starts the
|
|
183
|
+
clock regardless.
|
|
184
|
+
- OSV version ranges now feed rule 1, which can move a verdict to `fixed` when
|
|
185
|
+
the shipped version is at or past the advisory's fixed version.
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## [0.2.0] — 2026-09-17
|
|
190
|
+
|
|
191
|
+
The release that turns a sketch into something you could file with.
|
|
192
|
+
|
|
193
|
+
### Added
|
|
194
|
+
|
|
195
|
+
- **Buildroot ingest** — `legal-info/manifest.csv` for the inventory,
|
|
196
|
+
`pkg-stats.json` for CVE and CPE data, `<PKG>_IGNORE_CVES` read as a triage
|
|
197
|
+
signal.
|
|
198
|
+
- **Kernel configuration gating** — `--gate CONFIG_SYM`. A CVE whose vulnerable
|
|
199
|
+
code sits behind a symbol that is unset in the shipped `.config` is downgraded
|
|
200
|
+
from `affected` to `not_affected` with the
|
|
201
|
+
`vulnerable_code_not_in_execute_path` justification. Gating can only downgrade,
|
|
202
|
+
never upgrade, and the absence of gating data is never read as "not gated".
|
|
203
|
+
- **A real triage engine** (`triage.py`) replacing the 0.1 status lookup. Every
|
|
204
|
+
verdict carries a confidence level and the ordered list of rules that produced
|
|
205
|
+
it, each with the file it read.
|
|
206
|
+
- **Yocto `CVE_STATUS` reason mapping** — the reason string, not just the
|
|
207
|
+
patched/ignored/unpatched group, is read and mapped to the closed OpenVEX
|
|
208
|
+
justification vocabulary. This is where most of the false-positive reduction
|
|
209
|
+
lives.
|
|
210
|
+
- **CycloneDX `analysis.justification` mapping** — an SBOM that already carries
|
|
211
|
+
triage decisions no longer loses them on ingest.
|
|
212
|
+
- **Advisory version-range matching** — `--fixed-version`, with introduced and
|
|
213
|
+
last-affected bounds, using Debian ordering rules so
|
|
214
|
+
`1.2.3+git0+abcdef1234-r0` compares correctly against `1.2.4`.
|
|
215
|
+
- **Schema validation on every emit.** CSAF 2.0 and OpenVEX 0.2.0 documents are
|
|
216
|
+
validated against the vendored official schemas before they are written or
|
|
217
|
+
recorded as evidence. `--no-validate` opts out.
|
|
218
|
+
- **Three reporting stages**, not one: `--stage early_warning | notification |
|
|
219
|
+
final_report`, with later stages inheriting earlier fields.
|
|
220
|
+
- **Gap detection.** The dossier lists the mandatory fields that have no value,
|
|
221
|
+
first, before anything else. `cra24 report` exits 6 when the dossier is written
|
|
222
|
+
but not submittable, so a CI job can tell "not ready" from "crashed".
|
|
223
|
+
- **`cra24 init`** writes a configuration template with every field present.
|
|
224
|
+
- **`cra24 spec`** prints the SRP field set this release carries.
|
|
225
|
+
- **`cra24 doctor`** reports the installation: spec versions, bundled schemas,
|
|
226
|
+
whether validation is available, whether evidence signing is configured.
|
|
227
|
+
- **Optional HMAC over evidence records** via `CRA24_EVIDENCE_KEY`, raising the
|
|
228
|
+
bar from "an editor" to "someone who also has the key".
|
|
229
|
+
- **Dual licensing**: AGPL-3.0-only plus a commercial licence, with a CLA, a
|
|
230
|
+
commercial licence template, and an SPDX header on every source file enforced
|
|
231
|
+
by a test.
|
|
232
|
+
|
|
233
|
+
### Changed
|
|
234
|
+
|
|
235
|
+
- **The SRP field set moved out of code and into
|
|
236
|
+
`src/cra24/data/srp-fields.json`**, versioned, with its sources and its known
|
|
237
|
+
disagreements recorded. When ENISA moves the form, the fix is a data edit.
|
|
238
|
+
- **Product serialisation is deterministic.** `scanned_at` is stamped once at
|
|
239
|
+
ingest instead of at save time, so saving the same inventory twice produces
|
|
240
|
+
identical bytes and the evidence ledger does not record a spurious change.
|
|
241
|
+
- **Library code no longer calls `SystemExit`.** Everything raises from the
|
|
242
|
+
`Cra24Error` hierarchy; only `cli.py` turns those into exit codes.
|
|
243
|
+
- **The evidence ledger** gained sequence numbers, artefact re-hashing on verify,
|
|
244
|
+
and a `summary` view. Verification now reports every problem, not just the
|
|
245
|
+
first.
|
|
246
|
+
- CSAF output models the component *inside* the product with a
|
|
247
|
+
`default_component_of` relationship, carries purls in product identification
|
|
248
|
+
helpers, and emits a flag or threat for every `known_not_affected` product.
|
|
249
|
+
- OpenVEX output emits components as subcomponents of the product, and always
|
|
250
|
+
carries either a justification or an impact statement on `not_affected`.
|
|
251
|
+
|
|
252
|
+
### Fixed
|
|
253
|
+
|
|
254
|
+
- **A recipe whose packages ship under a different name is no longer dropped.**
|
|
255
|
+
`cve-check` reports at recipe granularity (`linux-raspberrypi`) while image
|
|
256
|
+
manifests list packages (`kernel-image-image`). The 0.1 ingest dropped the
|
|
257
|
+
recipe because its own name was absent from the manifest, which silently
|
|
258
|
+
removed every kernel CVE from the dossier. A recipe-to-package map built from
|
|
259
|
+
`license.manifest` fixes it. *This is the most consequential bug fixed in this
|
|
260
|
+
release; re-scan any 0.1 inventory.*
|
|
261
|
+
- Yocto `+gitAUTOINC+` version decoration is stripped correctly instead of
|
|
262
|
+
leaving `AUTOINC+<hash>` attached to the version.
|
|
263
|
+
- `-v` is accepted both before and after the subcommand.
|
|
264
|
+
|
|
265
|
+
### Field spec
|
|
266
|
+
|
|
267
|
+
- Initial versioned spec, `2026-09-17`. Reconstructed from ENISA's SRP pages, the
|
|
268
|
+
Commission's reporting guidance and two public field guides. Records two known
|
|
269
|
+
disagreements: whether severity is mandatory at 24 hours, and whether the
|
|
270
|
+
affected Member States field is "required" or "required if available".
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## [0.1.0] — 2026-09-17
|
|
275
|
+
|
|
276
|
+
Initial sketch: Yocto and SBOM ingest, a flat SRP field list, CSAF and OpenVEX
|
|
277
|
+
emit, a hash-chained evidence ledger.
|
|
278
|
+
|
|
279
|
+
[1.0.0]: https://github.com/cra24/cra24/releases/tag/v1.0.0
|
|
280
|
+
[0.4.0]: https://github.com/cra24/cra24/releases/tag/v0.4.0
|
|
281
|
+
[0.3.0]: https://github.com/cra24/cra24/releases/tag/v0.3.0
|
|
282
|
+
[0.2.0]: https://github.com/cra24/cra24/releases/tag/v0.2.0
|
|
283
|
+
[0.1.0]: https://github.com/cra24/cra24/releases/tag/v0.1.0
|
cra24-1.0.0/CLA.md
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# Contributor Licence Agreement
|
|
2
|
+
|
|
3
|
+
**Version 1.0, 17 September 2026.**
|
|
4
|
+
|
|
5
|
+
> **Not legal advice.** Adapted from the widely used Apache-style ICLA/CCLA
|
|
6
|
+
> pattern, rewritten for a dual-licensed project. Have a lawyer review it before
|
|
7
|
+
> you rely on it. Placeholders are marked `[LIKE THIS]`.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Why cra24 asks for this
|
|
12
|
+
|
|
13
|
+
cra24 is offered under two licences: the AGPL-3.0, and a paid commercial licence
|
|
14
|
+
(see `LICENSING.md`). Only the copyright holder can offer a work under a licence
|
|
15
|
+
other than the one it was received under.
|
|
16
|
+
|
|
17
|
+
If a contribution arrived under the AGPL alone, the project could no longer grant
|
|
18
|
+
the commercial licence over code containing it — one patch would quietly end the
|
|
19
|
+
business model, and with it the reason anyone is paid to maintain this.
|
|
20
|
+
|
|
21
|
+
So contributors grant a parallel licence. **You keep your copyright.** You are not
|
|
22
|
+
assigning anything. You are granting the project the right to distribute your
|
|
23
|
+
contribution under both licences, alongside your own unchanged right to do
|
|
24
|
+
whatever else you want with your own code.
|
|
25
|
+
|
|
26
|
+
If that trade is not one you want to make, that is a legitimate position. Open an
|
|
27
|
+
issue describing the change instead; a maintainer can implement it independently.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Individual Contributor Licence Agreement
|
|
32
|
+
|
|
33
|
+
You accept and agree to the following terms for your past, present and future
|
|
34
|
+
Contributions to cra24. Except for the licences granted here, you reserve all
|
|
35
|
+
right, title and interest in and to your Contributions.
|
|
36
|
+
|
|
37
|
+
### 1. Definitions
|
|
38
|
+
|
|
39
|
+
**"You"** means the copyright owner, or the legal entity authorised by the
|
|
40
|
+
copyright owner, entering into this agreement.
|
|
41
|
+
|
|
42
|
+
**"Contribution"** means any original work of authorship, including any
|
|
43
|
+
modification of an existing work, that is intentionally submitted by You to the
|
|
44
|
+
Project for inclusion in, or documentation of, any of its products.
|
|
45
|
+
|
|
46
|
+
**"Submitted"** means any form of electronic, verbal or written communication sent
|
|
47
|
+
to the Project or its maintainers, including on source code repositories, issue
|
|
48
|
+
trackers and mailing lists, but excluding communication conspicuously marked in
|
|
49
|
+
writing as **"Not a Contribution."**
|
|
50
|
+
|
|
51
|
+
**"Project"** means the cra24 project, and `Amr Ben Abdessalem (France)` as its steward.
|
|
52
|
+
|
|
53
|
+
### 2. Copyright licence
|
|
54
|
+
|
|
55
|
+
You grant to the Project and to recipients of software distributed by the Project
|
|
56
|
+
a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
57
|
+
copyright licence to reproduce, prepare derivative works of, publicly display,
|
|
58
|
+
publicly perform, sublicense and distribute Your Contributions and such derivative
|
|
59
|
+
works.
|
|
60
|
+
|
|
61
|
+
**This licence expressly includes the right to sublicense Your Contribution under
|
|
62
|
+
terms of the Project's choosing, including proprietary commercial terms**, as part
|
|
63
|
+
of the dual-licensing model described in `LICENSING.md`.
|
|
64
|
+
|
|
65
|
+
### 3. Patent licence
|
|
66
|
+
|
|
67
|
+
You grant to the Project and to recipients of software distributed by the Project
|
|
68
|
+
a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable patent
|
|
69
|
+
licence to make, have made, use, offer to sell, sell, import and otherwise
|
|
70
|
+
transfer the Work.
|
|
71
|
+
|
|
72
|
+
This licence applies only to those patent claims licensable by You that are
|
|
73
|
+
necessarily infringed by Your Contribution alone, or by the combination of Your
|
|
74
|
+
Contribution with the Work to which it was submitted.
|
|
75
|
+
|
|
76
|
+
If any entity institutes patent litigation alleging that Your Contribution, or the
|
|
77
|
+
Work it was submitted to, constitutes direct or contributory patent infringement,
|
|
78
|
+
any patent licences granted under this agreement to that entity terminate as of
|
|
79
|
+
the date such litigation is filed.
|
|
80
|
+
|
|
81
|
+
### 4. Your representations
|
|
82
|
+
|
|
83
|
+
You represent that:
|
|
84
|
+
|
|
85
|
+
- **(a)** You are legally entitled to grant the above licences.
|
|
86
|
+
- **(b)** Each Contribution is Your original creation.
|
|
87
|
+
- **(c)** If Your employer has rights to intellectual property You create, You
|
|
88
|
+
have received permission to make the Contribution on behalf of that employer,
|
|
89
|
+
or Your employer has waived such rights, or Your employer has executed the
|
|
90
|
+
Corporate CLA below.
|
|
91
|
+
- **(d)** Your Contribution includes complete details of any third-party licence
|
|
92
|
+
or other restriction of which You are personally aware and which is associated
|
|
93
|
+
with any part of it.
|
|
94
|
+
|
|
95
|
+
### 5. What you are not promising
|
|
96
|
+
|
|
97
|
+
You are not expected to provide support for Your Contributions.
|
|
98
|
+
|
|
99
|
+
**Unless required by applicable law or agreed in writing, You provide Your
|
|
100
|
+
Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND**,
|
|
101
|
+
either express or implied, including any warranty of title, non-infringement,
|
|
102
|
+
merchantability or fitness for a particular purpose.
|
|
103
|
+
|
|
104
|
+
### 6. Notification
|
|
105
|
+
|
|
106
|
+
You agree to notify the Project of any facts or circumstances of which You become
|
|
107
|
+
aware that would make these representations inaccurate in any respect.
|
|
108
|
+
|
|
109
|
+
### 7. Reciprocity
|
|
110
|
+
|
|
111
|
+
The Project undertakes that Your Contribution will remain available under the
|
|
112
|
+
AGPL-3.0, or a later version of the AGPL, in a publicly accessible repository, for
|
|
113
|
+
as long as the Project distributes it at all.
|
|
114
|
+
|
|
115
|
+
*This clause is not in the standard Apache ICLA. It is here because a CLA without
|
|
116
|
+
it asks a contributor to trust a promise that nobody wrote down: that the project
|
|
117
|
+
will not simply go closed once it has enough contributed code. This is that
|
|
118
|
+
promise, written down.*
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Corporate Contributor Licence Agreement
|
|
123
|
+
|
|
124
|
+
Where contributions are made by employees in the course of their employment, the
|
|
125
|
+
employer signs this instead of, or in addition to, the individual agreement.
|
|
126
|
+
|
|
127
|
+
The terms of sections 1 to 7 above apply, with "You" meaning the Corporation, plus:
|
|
128
|
+
|
|
129
|
+
### 8. Schedule of authorised contributors
|
|
130
|
+
|
|
131
|
+
The Corporation lists below the employees authorised to submit Contributions on
|
|
132
|
+
its behalf, and undertakes to keep the list current by written notice.
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
Corporation: ______________________________________
|
|
136
|
+
Registered address: ______________________________________
|
|
137
|
+
Company number: ______________________________________
|
|
138
|
+
|
|
139
|
+
Authorised contributors (name / email / repository handle):
|
|
140
|
+
1. ____________________________________________________
|
|
141
|
+
2. ____________________________________________________
|
|
142
|
+
3. ____________________________________________________
|
|
143
|
+
|
|
144
|
+
Point of contact: ____________________________________
|
|
145
|
+
Signed: ____________________ Date: __________
|
|
146
|
+
Name and title: ____________________________________
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## How to sign
|
|
152
|
+
|
|
153
|
+
**Individuals** — add a `Signed-off-by:` trailer to every commit, using your real
|
|
154
|
+
name and an email you control:
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
git commit -s -m "your message"
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Adding that trailer means:
|
|
161
|
+
|
|
162
|
+
> I certify that I have read the cra24 Individual Contributor Licence Agreement
|
|
163
|
+
> version 1.0, that I am entitled to grant the licences it describes, and that I
|
|
164
|
+
> grant them for this contribution.
|
|
165
|
+
|
|
166
|
+
The CI checks for the trailer. A first-time contributor is also asked, once, to
|
|
167
|
+
confirm in the pull request thread that they have read this document.
|
|
168
|
+
|
|
169
|
+
**Corporations** — send the completed schedule above to `amr.benabdessalem@gmail.com` before your
|
|
170
|
+
employees' first pull request.
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Records
|
|
175
|
+
|
|
176
|
+
Signed corporate agreements are retained by `Amr Ben Abdessalem (France)`. Sign-off
|
|
177
|
+
trailers live in the git history, which is the record for individual contributors.
|
|
178
|
+
|
|
179
|
+
Personal data in these records is processed on the basis of legitimate interest in
|
|
180
|
+
establishing the provenance of the code, retained for as long as the Project
|
|
181
|
+
distributes the Contribution, and is not used for any other purpose.
|
|
182
|
+
`[CONFIRM YOUR GDPR POSITION AND ADD A PRIVACY CONTACT.]`
|