Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .fusa-reqs.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
{"id":"REQ-HARA007","title":"cfusa hara show displays hazard entries","standard":"ISO 26262-3","level":"ASIL-A"},
{"id":"REQ-HARA008","title":"cfusa hara asil computes ASIL from S/E/C","standard":"ISO 26262-3","level":"ASIL-A"},
{"id":"REQ-HARA009","title":"ASIL table follows ISO 26262-3:2018 Table 4","standard":"ISO 26262-3","level":"ASIL-D"},
{"id":"REQ-HARA010","title":"check gates on stored hazard ASIL matching the S x E x C table","standard":"ISO 26262-3","level":"ASIL-D"},
{"id":"REQ-ENG001","title":"Engine registers rules up to CFUSA_MAX_RULES","standard":"ISO 26262","level":"ASIL-A"},
{"id":"REQ-ENG002","title":"Engine runs all registered rules","standard":"ISO 26262","level":"ASIL-A"},
{"id":"REQ-ENG003","title":"Engine can run rules by category","standard":"ISO 26262","level":"ASIL-A"},
Expand Down Expand Up @@ -338,14 +339,23 @@
{"id":"REQ-HARA-SCHEMA001","title":"cfusa hara init scaffolds empty operationalSituations/hazards/safetyGoals collections, never dummy rows","standard":"x-FuSa spec §1.2.5","level":"ASIL-D"},
{"id":"REQ-HARA-SCHEMA002","title":"cfusa hara show --format json reports completeness including safetyGoalsWithFssrRefs and danglingReferences","standard":"x-FuSa spec §1.2.5","level":"ASIL-B"},
{"id":"REQ-HARA-SCHEMA003","title":"cfusa hara show detects and gates on FUSA-STUB001 placeholder text in hazard/safety-goal descriptions","standard":"x-FuSa spec §1.6.1","level":"ASIL-D"},
{"id":"REQ-HARA-SCHEMA004","title":"cfusa hara show --format json is a verbatim passthrough of hazards[].source/situations/safetyGoals, safetyGoals[].hazards/safeState, and the document attestation","standard":"x-FuSa spec §9.2","level":"ASIL-B"},

{"id":"REQ-FMEA-SCHEMA001","title":"cfusa fmea --format json emits ratingScale, failureMode/effect/cause, actionPriority, and summary.componentsInProject/coveragePct","standard":"x-FuSa spec §9.2","level":"ASIL-B"},
{"id":"REQ-FMEA-SCHEMA002","title":"cfusa fmea failureMode/effect/cause text varies per function rather than one fixed string for every entry","standard":"x-FuSa spec §1.6.1","level":"ASIL-B"},
{"id":"REQ-FMEA-SCHEMA003","title":"cfusa fmea.json standard field is the canonical lowercase id (iso26262), not a display string","standard":"x-FuSa spec §2.4.1","level":"ASIL-B"},
{"id":"REQ-FMEA-SCHEMA004","title":"cfusa fmea.json entries[].file is project-relative regardless of whether --dir is relative or absolute","standard":"x-FuSa spec §4","level":"ASIL-B"},
{"id":"REQ-FMEA-SCHEMA005","title":"cfusa fmea excludes standard-library calls and string-literal text from componentsInProject/entries","standard":"x-FuSa spec §1.6 rule 4","level":"ASIL-B"},
{"id":"REQ-FMEA-COV001","title":"cfusa fmea --min-coverage N exits 1 when summary.coveragePct < N (N=0 disables the gate)","standard":"x-FuSa spec §9.2","level":"ASIL-B"},
{"id":"REQ-FMEA-COV002","title":"cfusa fmea.json summary.coveragePct never exceeds 100 even with a non-trivial test-source tree","standard":"x-FuSa spec §9.2","level":"ASIL-B"},
{"id":"REQ-FMEA-ATTEST001","title":"cfusa fmea --attest <reviewer> stamps a valid §1.6.2 attestation that suppresses FUSA-STUB002","standard":"x-FuSa spec §1.6.2","level":"ASIL-B"},
{"id":"REQ-FMEA-OUTPUT001","title":"cfusa fmea --output <file> writes exactly that path, distinct from --output-dir","standard":"x-FuSa spec §9.2","level":"ASIL-B"},

{"id":"REQ-TARA-SCHEMA001","title":"cfusa tara --format json emits threats[].impact as an SFOP object and summary.assetInventoryMethod","standard":"x-FuSa spec §9.2","level":"ASIL-B"},
{"id":"REQ-TARA-SCHEMA002","title":"cfusa tara.json standard field is the canonical lowercase id (iso21434), impact.* uses the critical/major/moderate/negligible closed enum, and risk is derived from the spec's combination table","standard":"x-FuSa spec §9.2","level":"ASIL-B"},
{"id":"REQ-TARA-SCHEMA003","title":"cfusa tara.json threats[].location.file is project-relative and excludes standard-library calls/string-literal text","standard":"x-FuSa spec §4","level":"ASIL-B"},
{"id":"REQ-TARA006","title":"cfusa tara summary rolls up assetsAnalyzed/assetsInProject/coveragePct/assetInventoryMethod","standard":"ISO 21434","level":"ASIL-B"},
{"id":"REQ-TARA-COV001","title":"cfusa tara.json summary.coveragePct never exceeds 100 even with a non-trivial test-source tree","standard":"x-FuSa spec §9.2","level":"ASIL-B"},

{"id":"REQ-SC002","title":"cfusa safety-case --format json emits nodes[]/edges[]/completeness using the six GSN node types","standard":"x-FuSa spec §9.2","level":"ASIL-B"},
{"id":"REQ-SC003","title":"cfusa safety-case solution nodes cite evidence only for files that actually exist in the project","standard":"x-FuSa spec §9.2","level":"ASIL-B"},
Expand All @@ -354,6 +364,7 @@
{"id":"REQ-SAS-SCHEMA001","title":"cfusa sas --format json emits checklist[]/summary and always writes the sas.md companion","standard":"x-FuSa spec §9.3","level":"ASIL-A"},

{"id":"REQ-SCI-SCHEMA001","title":"cfusa sci --format json emits artifacts[].hash as sha256:-prefixed per x-FuSa spec §2.7","standard":"x-FuSa spec §2.7","level":"ASIL-A"},
{"id":"REQ-SCI-SCHEMA002","title":"cfusa sci.json artifacts[].file is project-relative even when --dir is given as an absolute path","standard":"x-FuSa spec §4","level":"ASIL-A"},

{"id":"REQ-FSR-CHECK001","title":"cfusa check/lint shall not suppress or omit any finding for which the rule engine is configured to detect (functional safety requirement decomposing .fusa-hara.json SG-001)","standard":"ISO 26262-3","level":"ASIL-C"},
{"id":"REQ-FSR-CHECK002","title":"cfusa check shall keep its false-positive rate low enough, via the disposition system, that it does not cause systematic check-disabling (functional safety requirement decomposing .fusa-hara.json SG-002)","standard":"ISO 26262-3","level":"ASIL-C"}
Expand Down
85 changes: 85 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,91 @@ and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.

## [Unreleased]

## v0.5.47 — 2026-07-28

x-FuSa spec v1.15.0 adoption + deep-audit bug-fix sprint (issues #73-80):
`hara`/`fmea`/`tara`/`sci` schema-conformance fixes found by running the
tool against its own codebase and diffing real output against the spec.

### Added
- **HARA006 `check` engine rule.** `risk.asil` is now cross-checked against
the ISO 26262-3 Table 4 S x E x C derivation both as a `check`-gating
`Finding` (HARA006) and in `hara --format json`'s new
`completeness.asilMismatches` count — previously the mismatch only
surfaced as a `hara show` (text) warning line that never affected any
exit code or machine-readable output (#74). The S x E x C table itself is
now `src/asil.c`'s shared `cfusa_compute_asil()`, used by both call sites
instead of a copy local to `cmd_hara.c`.
- **`hara --format json` verbatim passthrough.** `hazards[].source`/
`situations`/`safetyGoals` and `safetyGoals[].hazards`/`safeState` are no
longer silently dropped, and a document-level `attestation` (when present
in `.fusa-hara.json`) is now passed through — closing the gap between
what `hara show` (text) already displayed and what a consumer of the
JSON contract could actually see (#73).
- **`cfusa fmea --output <file>`.** `fmea` previously defined only
`--output-dir <dir>`, so GNU `getopt_long`'s unambiguous-prefix matching
silently treated `--output <path>` (the exact form the CLI synopsis in
§9.2 documents) as an abbreviation of `--output-dir`, writing a bogus
`<path>/fmea.json` and failing with a confusing error instead of either
working or rejecting cleanly (#79).
- Shared `src/utils.c` helpers: `cfusa_relativize_path()` (the one
canonical project-relative-path implementation, replacing ad hoc copies
in `cfusa_report_add()`/`cmd_trace.c`), `cfusa_is_test_source_file()`,
`cfusa_is_stdlib_call()`, and `cfusa_extract_call_name()` — the last two
centralise the "does this line look like a real call/definition site"
heuristic previously duplicated (and independently under-guarded) in
`cmd_fmea.c`'s `fmea_line()` and `cmd_tara.c`'s `asset_line()`, per the
x-FuSa spec §1.6 rule 4 implementation note.
- Regenerated this repo's own `fmea.json`/`fmea.csv`, `tara.json`/`tara.md`,
and `safety-case.json`/`safety-case.md` against the fixes below —
dogfooding, same convention as v0.5.46.

### Fixed
- **`fmea.json`/`tara.json` picked up standard-library calls and
string-literal text as project components/assets (#78).** The scanner's
naive paren-based heuristic found the first `(` on a line without regard
to whether it sat inside a quoted string (misreading a qualification
test-case description like `"strcpy() triggers CY001"` as a call to a
function named `"strcpy`, leading-quote included), and never excluded
well-known libc calls (`fprintf`/`snprintf`/`printf`/`malloc`/`memcpy`/...
— 67 of 370 entries, 18%, in this repo's own previously-committed
`fmea.json`). `cfusa_extract_call_name()` now requires the `(` to be
outside a string literal and excludes standard-library identifiers
outright. `cfusa_walk_sources()` also skipped only a fixed directory-name
enum (`build`/`vendor`/`build-cov`/`node_modules`); a local working tree
with other build-type variants side by side (`build-asan`,
`build_fortify`, ...) had every one of them scanned as project source
too, picking up CMake's own generated `CompilerIdC` probe. Both are §1.6
rule 4 "real referents only" violations; `cfusa_walk_sources()` now skips
any `build`/`build-*`/`build_*` directory, matching this project's own
`.gitignore` convention.
- **`fmea.json`/`tara.json` truncated `file` to a bare basename; `sci.json`
emitted an absolute path when `--dir` was given absolute (#77).**
`cfusa_relativize_path()` now relativizes against the literal `--dir`
value used to build each scanned path (deliberately *not*
`realpath(dir)` — see its doc comment: `path` is always built by
concatenating the literal `--dir`, and resolving symlinks first can
silently break the prefix match, e.g. macOS aliases `/tmp` to
`/private/tmp`), applied to `fmea`/`tara`'s entry `file` and `sci`'s
`artifacts[].file`.
- **`fmea.json`/`tara.json` `standard` was a citation string, not the
canonical id (#75).** `"IEC 60812:2018 / ISO 26262-5"` -> `"iso26262"`;
`"ISO/SAE 21434:2021 Clause 15"` -> `"iso21434"`, matching
`safety-case.json`'s existing (correct) convention and x-FuSa spec
§2.4.1's "never a display string" rule.
- **`tara.json` `impact.*` used `high|medium|low`, and `risk` was an ad hoc
score (#76).** The four category profiles now emit the v1.14.1 closed
enum (`critical|major|moderate|negligible`), and `risk` is a literal
lookup against the x-FuSa spec §9.2 combination table (highest-ranked
SFOP impact x `attackFeasibility`) instead of an independently-invented
`feasibility_rank x impact_rank` numeric threshold that didn't correspond
to the table's cells.
- **`summary.coveragePct` defensive clamp (fmea/tara, #80).** Added
`if (coveragePct > 100) coveragePct = 100;` to both commands per the
x-FuSa spec §9.2 MUST, plus a regression test with a non-trivial
test-source tree on each (a fixture with no `test_*.c`-equivalent
directory can't exercise the bug this clamp guards against).

## v0.5.46 — 2026-07-28

x-FuSa spec v1.13.0/v1.14.0 conformance sprint (issue #71): `hara`/`fmea`/
Expand Down
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.16)
project(cfusa
VERSION 0.5.46
VERSION 0.5.47
DESCRIPTION "C functional safety toolkit"
LANGUAGES C
)
Expand Down Expand Up @@ -38,6 +38,7 @@ add_library(cfusa_core STATIC
src/utils.c
src/cfusa_runtime.c
src/qualitybar.c
src/asil.c
)
target_include_directories(cfusa_core PUBLIC include)
set_target_properties(cfusa_core PROPERTIES
Expand Down
Loading
Loading