You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
components: structured disposition to replace skip-reason
The free-text `R <text>` skip-reason was captured but never surfaced,
and only 8 components emitted it. Replace it with a structured
disposition, `R cat=<category> [gate=<token>] [msg="<text>"]`, in a
closed vocabulary (mitigation / absent / disabled / inconclusive) that
refines the exit code. Typed emitters return the exit code the category
implies, so the two channels cannot disagree; a mitigation names the
control it confirmed.
Surface it per-component in JSON, as a mitigation digest in default text
and markdown, in full under --verbose, and as confirmed_mitigations in
the hardening report. posture-diff now flags a confirmed mitigation that
stopped blocking a leak; posture-summary gains a defenses column. Add a
parse_disposition fuzz harness (and fix an undefined LINE_LEN in two
sibling harnesses). Update CONTRIBUTING and the usage/architecture docs.
A leak or probe that determines it cannot run — or ran and found nothing worth
186
-
attributing to a specific gate — calls `kasld_skip_reason(text)`, which emits a
187
-
short `R` skip-reason line (e.g. "KPTI enabled", "not an Intel CPU"). The
188
-
orchestrator captures it onto the per-component log; it is recorded metadata,
189
-
never engine evidence, and is orthogonal to the exit code: the code names the
190
-
outcome class, the reason names the specific gate within it.
187
+
A leak or probe that ends without a tagged result can report *why* with a
188
+
**disposition** — a short `R` line in a closed category that refines the exit
189
+
code (recorded metadata, never engine evidence). The category carries the
190
+
distinction the exit code cannot: an unavailable technique blocked by a
191
+
*defensive control on the target* versus one that merely lacks a *prerequisite
192
+
on this host*, and an empty run that is a deliberate opt-out versus an honest
193
+
"ran, no clean signal, cannot prove why". The typed emitters emit the line and
194
+
return the exit code the category implies, so the two channels cannot disagree:
195
+
196
+
| Emitter | Meaning | Returns |
197
+
|---|---|---|
198
+
|`kasld_disp_mitigation(gate, msg)`| A defensive control foiled it; `gate` names the control (`kpti`, a `CONFIG_` id, a CVE id) and is **required**|`KASLD_EXIT_UNAVAILABLE`|
199
+
|`kasld_disp_mitigation_denied(gate, msg)`| A control *denied the source* (the access-denied variant) |`KASLD_EXIT_NOPERM`|
200
+
|`kasld_disp_absent(msg)`| An attacker prerequisite is missing on this host |`KASLD_EXIT_UNAVAILABLE`|
201
+
|`kasld_disp_disabled(msg)`| Deliberate operator opt-out (needs a flag/env) |`KASLD_EXIT_UNAVAILABLE`|
202
+
|`kasld_disp_inconclusive(msg)`| Ran, no clean signal, cannot prove why |`0`|
203
+
204
+
Use `kasld_disposition(cat, gate, msg)` (no return value) where the exit code is
205
+
decided elsewhere — inside a helper or a loop. A mitigation with no gate is a
206
+
bug and emits nothing. Emit a disposition only when it soundly classifies the
207
+
null result beyond the exit code — above all, a confirmed mitigation; a
208
+
component that merely found no matching entry emits nothing. A `mitigation`
209
+
disposition is confirmed active in the hardening report; the mitigation category
210
+
is surfaced in default output, all categories under `--verbose`, and each
0 commit comments