Repository navigation
Releases: SoundMatt/c-FuSa
Release list
v0.6.2
cfusa v0.6.2
Architecture-plan loop: eleven tracked improvement issues (#203–#213),
eight shipped across eight PRs (#215–#218, #220–#223); #206/#207
deliberately deferred per their own issue scoping; #211 (Windows/MSVC)
resolved as a scoping decision rather than an implementation — see
below. Minor-version-worthy in spirit (new user-facing flags/commands),
kept as a patch bump per policy. 47/47 test suites pass, self-check
clean (0 errors).
Added
- A shared, comment/string-literal-aware line-stripping primitive
(cfusa_lex_strip_line(),include/cfusa/lex.h/src/lex.c) replacing
ad hoc per-rule comment/string state machines — space-blanks (never
deletes) comment/string content so column positions are preserved and
tokens never glue together across a stripped comment. (#203) - A single tree-walk / single file-read engine for line-scan rules
(cfusa_engine_register_line_rule()/cfusa_engine_run_line_rules())
— collapsed 54 independentcfusa_walk_sources()call sites (one per
rule) into one walk-and-dispatch pass percfusa check/lint/
analyze/cyberrun. (#204) #if 0preprocessor-lite awareness — code inside an
unconditionally-disabled#if 0block is no longer scanned by
line-based rules, removing a class of false positives on intentionally
dead/documentation code. (#205)cfusa baselineand.fusa-baseline.json— snapshot a project's
current findings to exclude them from the exit-code gate, so an
existing codebase can adopt c-FuSa without gating on its full
pre-existing backlog. Composes with.fusa-dispositions.json. (#208)cfusa check --changed-since <git-ref>— scopes a report to only
findings on lines actually changed since<ref>(viagit diff --unified=0), for gating a pull request on newly-introduced findings
rather than a project's full existing backlog. Independent of, and
composable with, baseline/dispositions. (#209)cfusa fixremediation-guidance coverage expanded from 19 to the
full 39 lint/analyze/cyber rules, plus a real--dry-run/--apply
auto-rewrite forCFUSA-CY006(free-without-NULL) — conservatively
scoped to a barefree(<simple-lvalue>);call, and safe to re-run
since it skips a pointer already NULL'd on the next line. (#210)cfusa explain <RULE-ID>(andcfusa explain --list) — prints a
rule's category, standard/clause citation, description, and remediation
guidance in one place; rule-id lookup is case-insensitive and tolerates
a missingCFUSA-prefix. (#212)- A first-party GitHub Action (
action.yml, usable asuses: SoundMatt/c-FuSa@<tag>) — installs a pinnedcfusarelease binary,
runscfusa check, and uploads SARIF to the code-scanning tab, with
dir/version/strict/changed-since/fail-on-errorinputs.
Dogfooded against this repo itself in CI
(.github/workflows/action-smoke-test.yml). (#213)
Documented
- Windows/MSVC support was audited and deliberately deferred, not
implemented.fork()/pipe()/execvp()subprocess spawning (4
files), theopendir()/readdir()-based tree walk underlying every
rule, andgetopt_long(all 44cmd_*.cfiles) have no direct Windows
equivalent — this is a systemic, cross-cutting port, not a bounded
feature. WSL2 already runs today'scfusaunmodified and is the
recommended path; see issue #211 for the full audit and rationale.
Installation
# Linux (amd64)
curl -Lo cfusa https://github.com/SoundMatt/c-FuSa/releases/download/v0.6.2/cfusa-linux-amd64
chmod +x cfusa && sudo mv cfusa /usr/local/bin/
# macOS (arm64)
curl -Lo cfusa https://github.com/SoundMatt/c-FuSa/releases/download/v0.6.2/cfusa-darwin-arm64
chmod +x cfusa && sudo mv cfusa /usr/local/bin/
# From source
cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --install buildVerify
cfusa version
cfusa qualifyWhat's Changed
- feat: shared lexer/classifier replacing per-rule comment/string state machines by @SoundMatt in #215
- feat: single-pass walk-and-lex engine for line-scan rules by @SoundMatt in #216
- feat: #if 0 preprocessor-lite awareness in the shared lexer by @SoundMatt in #217
- feat: findings baseline / suppress-existing-debt mode by @SoundMatt in #218
- feat: git-diff-scoped analysis (cfusa check --changed-since) by @SoundMatt in #220
- feat: expand cfusa fix rule coverage + CY006 real autofix by @SoundMatt in #221
- feat: cfusa explain command by @SoundMatt in #222
- feat: first-party GitHub Action for cfusa check + SARIF upload by @SoundMatt in #223
- chore: bump v0.6.1 -> v0.6.2 by @SoundMatt in #224
Full Changelog: v0.6.1...v0.6.2
v0.6.1
cfusa v0.6.1
Forty-three fixes from a 40-agent deep-audit sweep of the codebase
(#141–#182) plus one more found and fixed the same session (#187).
Patch version bump — precision/correctness fixes only, no new
user-facing flags or behaviors. Every fix ships with regression tests
verified to fail against the pre-fix code and pass against the fix;
44/44 test suites pass and the self-check is clean.
Fixed
- Disposition JSON loading was brittle to incidental whitespace
around field values in.fusa-dispositions.json/.fusa-qualitybar.json/
HARA files — replaced ad hoc field extraction with a shared
whitespace-tolerant JSON string-field helper. (#143, #159, #175, #176) cfusa disposition addwasn't atomic and could corrupt the
dispositions file under concurrent writes, and didn't handle a
bare-array file shape. Now writes via a locked, atomic
temp-file-plus-rename, with a bare-array merge fallback. (#144, #158)- DISP001 matched on a whole-file substring instead of the real
fingerprint-scoped disposition mechanism, so an unrelated finding
whose message happened to mention a disposed rule id could be wrongly
suppressed. (#148) project_rootwasn't set consistently across commands, so the
same finding could get different fingerprints depending on which
command produced it — breaking cross-command disposition matching.
(#153)cmd_req.cresolved the wrong requirements filename in some code
paths,--sec-testeddidn't gate on the real tested count, and
Metric 1 could disagree with the underlying data. Canonical
.fusa-reqs.jsonresolution with legacy fallback; a real
--sec-testedgate. (#146, #147, #166)- Five CFUSA-CY rules (CY003/CY004/CY006/CY007/CY019) matched
dangerous-function names without identifier-boundary checks,
false-positiving on any name merely containing the pattern as a
substring. Switched to a shared boundary-aware matcher
(cfusa_find_token_outside_string()). (#154, #155, #156, #157, #173) cmd_lint.c's L001/L002/L003/L006 had precision and safety gaps:
L001'sstrncpycould leave an unterminated buffer; L002 only matched
gotowhen it started the line; L003/L006 had no persistent
block-comment tracking across lines, so multi-line comments without a
leading*on continuation lines were scanned as code. (#161, #162,
#163, #177)- The legacy
REQ:scanner andcfusa_config_is_excluded()matched
substrings without boundary checks, e.g. excludingsrc/rebuild_utils.c
purely because it contains "build". Anchored to identifier/path-segment
boundaries. (#174, #180) cmd_analyze.c's A001/A003/A006/A007 had false-positive/negative
precision issues: A003 missed multi-declarator lines, A006 matched
pointer-arithmetic incorrectly, A007 missed some unchecked-fclose
sites. (#149, #150, #151, #169)- Silent-truncation trio:
cfusa coverage's lcov parser could
misread an empty/unreadable file as 100% coverage; the HLR/LLR arrays
were capped at a fixed 512 entries with no warning; HARA's nested
reference arrays silently dropped entries past their cap. All three
now fail loudly or warn instead of silently under-reporting. (#142,
#160, #167) report.chad internal-consistency and formatting gaps: the
printed Result line didn't account for--strict; summary
tables/top-rules didn't exclude dispositioned findings; JSON/CSV
output had buffer-sizing and escaping issues. A new RFC 4180 CSV
writer was added. (#164, #165, #178, #179)- A failed report write silently exited 0 instead of the documented
exit code 3. (#141) cmd_hara.c's top-level JSON parsing was key-order-dependent —
reorderingoperationalSituations/hazards/safetyGoalsin the
source file could scope a scan incorrectly. Fixed via depth-1-bounded
bracket matching that no longer depends on key order. (#145)cfusa_config_save()only persisted the first declared standard
when multiple were set via--standard a,b, silently dropping the
rest on every re-save. (#168)--dal DAL-Dsilently discarded an explicit--threshold
(zeroing it instead of leaving it alone, asymmetric with how
--asil QMalready behaves), and--dal DAL-A/--asil ASIL-D's
100%-MC/DC requirement wasn't reflected in--mcdc-threshold,
letting a weaker explicit threshold silently pass. (#152, #172)- Only 3 of the ~41 commands'
getopt_longloops fully reset BSD's
optreset/glibc'snextcharbetween invocations — a bare
optind = 1doesn't fully clear either, risking stale-state misparses
across the repeated, in-process invocation pattern this project's own
test suite (and any embedding caller) uses. Applied the full
platform-reset block to every command. (#170, #171) - COUP001's
extern-variable match was unanchored and
comment-unaware, false-positiving on prose mentioning "extern"
inside a multi-line comment continuation line; COUP001/COUP002/
COMP001 all hardcodedreturn 0regardless of findings added,
breaking therun()-returns-finding-count contract every other rule
follows. (#181, #182) - CFUSA-L004's recursion detector had no comment-awareness,
misreporting a function as recursive when a comment inside its body
merely mentioned its own name. (#187)
Installation
# Linux (amd64)
curl -Lo cfusa https://github.com/SoundMatt/c-FuSa/releases/download/v0.6.1/cfusa-linux-amd64
chmod +x cfusa && sudo mv cfusa /usr/local/bin/
# macOS (arm64)
curl -Lo cfusa https://github.com/SoundMatt/c-FuSa/releases/download/v0.6.1/cfusa-darwin-arm64
chmod +x cfusa && sudo mv cfusa /usr/local/bin/
# From source
cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --install buildVerify
cfusa version
cfusa qualifyWhat's Changed
- fix: whitespace-tolerant JSON field extraction for dispositions/qualitybar/hara by @SoundMatt in #183
- fix: atomic, race-free disposition writes + bare-array merge fallback by @SoundMatt in #184
- fix: DISP001 defers to the real fingerprint-scoped disposition mechanism by @SoundMatt in #185
- fix: set project_root consistently so fingerprints agree across commands by @SoundMatt in #186
- fix: cmd_req canonical filename + real sec-tested gate + Metric 1 consistency by @SoundMatt in #188
- fix: identifier-boundary checks across 5 cyber rules (CY003/4/6/7/19) by @SoundMatt in #189
- fix: cmd_lint.c hardening — L001/L002/L003/L006 precision + safety fixes by @SoundMatt in #190
- fix: identifier-boundary matching for legacy REQ: scanner + exclude_dirs by @SoundMatt in #191
- fix: cmd_analyze.c hardening — A001/A003/A006/A007 precision fixes by @SoundMatt in #192
- fix: silent-truncation trio — lcov coverage, HLR/LLR arrays, hara nested refs by @SoundMatt in #193
- fix: report.c consistency + buffer/format fixes (Result/SUMMARY/JSON/CSV) by @SoundMatt in #194
- fix: report-write failures now exit 3, matching the documented contract by @SoundMatt in #195
- fix: cmd_hara.c top-level parsing immune to key reordering by @SoundMatt in #196
- fix: cfusa_config_save() persists every declared standard, not just [0] by @SoundMatt in #197
- fix: coverage DAL-D discards explicit thresholds; DAL-A/ASIL-D don't floor MC/DC threshold by @SoundMatt in #198
- fix: getopt_long platform-reset sweep across all CLI commands by @SoundMatt in #199
- fix: COUP001 anchored extern match + comment-awareness; COUP001/COUP002/COMP001 return-value contract by @SoundMatt in #200
- fix: CFUSA-L004 self-call detector is comment-aware by @SoundMatt in #201
- chore: bump v0.6.0 -> v0.6.1 by @SoundMatt in #202
Full Changelog: v0.6.0...v0.6.1
v0.6.0
cfusa v0.6.0
Nine fixes: seven from an open-issue sweep (#128, #124, #126, #97, #127,
#125, #122) plus two more (#129, #137) found and fixed the same session.
Minor version bump — includes new user-facing flags/behaviors, not just
bug fixes.
Fixed
cfusa qualify'squalified/qualificationBadgeJSON fields could
disagree (qualified: truenext toqualificationBadge: "unqualified") since they were computed independently.qualifiednow
requires both passing self-tests AND a declared--qualification-method.
(#128)cmd_hara.c'ssplit_array()silently dropped any hazard/safety-goal
JSON element >=511 bytes (fixed 512-byte stack buffer, no warning) — a
real HARA document could read 0 hazards. Now heap-allocates each element
at its exact length; the (generous) entry-count cap now warns instead of
silently truncating. (#124)- CFUSA-A003 (signed/unsigned vs
sizeof, CERT INT02-C) was a
near-100% false-positive rate on real code — purely syntactic, no type
awareness. Now does a two-pass scan for locally-visible
size_t/unsigned-family names before flagging; self-scan on this repo
went from 22 to 2 findings. (#126) cfusa safety-casehardcoded exact lowercase evidence filenames
(hara.md,safety-plan.md, etc.), case-sensitive viastat()— broke
on Linux CI/release for projects naming files e.g.HARA.md. New shared
cfusa_find_file_ci()does a real case-insensitive directory-listing
match. (#97)cfusa coverage --mcdc-fileparsed a schema that never matched real
llvm-cov exportoutput, so every genuine export reported 0 MC/DC
conditions. Fixed and verified against an actual capturedllvm-cov exportrun (both a fully-covered and zero-covered case). (#129)
Added
cfusa fixremediation guidance for CFUSA-CY006 (free-without-NULL,
CWE-416/CERT-C MEM30-C). (#127)cfusa trace --func-coverage-strict— a genuinely per-function
annotation-density gate (a//cfusa:reqtag directly above the
function's own definition), additive alongside the unchanged file-level
--func-coverage. (#125).fusa-dispositions.jsonis now enforced, not just logged.
cfusa check/cfusa lintload it and exclude accept/mitigate-action
findings (matched by fingerprint, never rule-wide) from the exit-code
gate — the finding stays visible, tagged inline, and its own summary
bucket.cfusa disposition add --fingerprint <sha256:...>is new.
(#122)cfusa coverage --branch-threshold <pct>— an independent
branch-coverage regression floor, separate from--threshold's
line-only gate; acts as a floor alongside--dal/--asil(never
weakens their fixed-100% branch requirement, only raises it if
stricter). (#137)
Installation
# Linux (amd64)
curl -Lo cfusa https://github.com/SoundMatt/c-FuSa/releases/download/v0.6.0/cfusa-linux-amd64
chmod +x cfusa && sudo mv cfusa /usr/local/bin/
# macOS (arm64)
curl -Lo cfusa https://github.com/SoundMatt/c-FuSa/releases/download/v0.6.0/cfusa-darwin-arm64
chmod +x cfusa && sudo mv cfusa /usr/local/bin/
# From source
cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --install buildVerify
cfusa version
cfusa qualifyWhat's Changed
- fix: CFUSA qualify no longer reports self-contradictory qualified/badge (#128) by @SoundMatt in #130
- fix: cmd_hara split_array() no longer silently drops oversized entries (#124) by @SoundMatt in #131
- fix: CFUSA-A003 precision — no longer flags already-unsigned operands (#126) by @SoundMatt in #132
- fix: cfusa safety-case matches evidence filenames case-insensitively (#97) by @SoundMatt in #133
- feat: cfusa fix adds remediation guidance for CFUSA-CY006 (#127) by @SoundMatt in #134
- feat: cfusa trace --func-coverage-strict, a genuinely per-function gate (#125) by @SoundMatt in #135
- feat: wire .fusa-dispositions.json into cfusa check/lint enforcement (#122) by @SoundMatt in #136
- fix: cfusa coverage --mcdc-file parses the real llvm-cov export schema (#129) by @SoundMatt in #138
- feat: cfusa coverage --branch-threshold, an independent branch gate (#137) by @SoundMatt in #139
- chore: bump v0.5.54 -> v0.6.0 by @SoundMatt in #140
Full Changelog: v0.5.54...v0.6.0
v0.5.54
cfusa v0.5.54
Three fixes from a direct quality review: unchecked fclose() return values,
a CFUSA-A006 false-positive class, and CFUSA-L003 precision + ASIL-scaled
severity.
Fixed
- All previously-flagged CFUSA-A007 (
unchecked fclose()) sites now check
the return value. 39 sites across 9 files touched this session; product
code gets real error handling (perror/fprintf(stderr, ...)), test code
fails loudly viaTEST_FAIL_MESSAGE. - CFUSA-A006 ("pointer arithmetic") no longer fires on coincidental,
unrelated*/++/--/+=/-=co-occurrence on the same line. Was a
same-line-proximity heuristic with no correlation check between the
dereferenced/declared pointer and the incremented variable; now requires
the same identifier on both sides. Project-wide: 545 → 141 findings (a 74%
reduction), each verified by hand as a genuine unrelated-token coincidence,
not a missed real finding. - CFUSA-L003 ("dynamic memory") no longer fires on custom
_free()-suffixed
functions or string-literal text. Was a plain substring match, so
free(also matched inside e.g.cfusa_report_free(). Project-wide:
464 → 133 findings (61% were this false-positive class). - CFUSA-L003 severity is now ASIL-scaled. ISO 26262-6 lists avoiding
dynamic memory allocation as "highly recommended" at ASIL-C/D but only
"recommended" at QM/A/B; a declared ASIL-C/D project now gets a hard
SEV_ERRORinstead of the uniformSEV_WARNINGevery project got before.
Sharedcfusa_declared_asil_rank()(moved from acmd_misra.c-local
helper intoseverity.h) so this and the accredited-tool note (v0.5.52)
don't drift independently.
Logged, not yet built
- Issue #122: wire
.fusa-dispositions.jsonintocfusa check/lint
enforcement. Dispositions are currently a standalone audit log — logging
one doesn't suppress the finding or affect the exit-code gate.
Installation
# Linux (amd64)
curl -Lo cfusa https://github.com/SoundMatt/c-FuSa/releases/download/v0.5.54/cfusa-linux-amd64
chmod +x cfusa && sudo mv cfusa /usr/local/bin/
# macOS (arm64)
curl -Lo cfusa https://github.com/SoundMatt/c-FuSa/releases/download/v0.5.54/cfusa-darwin-arm64
chmod +x cfusa && sudo mv cfusa /usr/local/bin/
# From source
cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --install buildVerify
cfusa version
cfusa qualifyWhat's Changed
- fix: check fclose() return value at all previously-flagged CFUSA-A007 sites by @SoundMatt in #119
- fix: CFUSA-A006 false-positives from coincidental *, ++/--/+=/-= co-occurrence by @SoundMatt in #120
- fix: CFUSA-L003 precision + ASIL-scaled severity by @SoundMatt in #121
- chore: bump v0.5.53 -> v0.5.54, doc accuracy fixes by @SoundMatt in #123
Full Changelog: v0.5.53...v0.5.54
v0.5.53
cfusa v0.5.53
Two MC/DC gate honesty fixes, found during a direct quality review of c-FuSa's
MC/DC support (not filed as a separate issue — fixed on request).
Fixed
cfusa coverage --mcdc-fileno longer silently passes on an empty
parse. A file that parses to zero MC/DC condition records used to
return a PASS ("nothing to fail") — indistinguishable, purely from
content, from a wrong path, a truncated file, or a future LLVM
export-format change the tool's string-scan no longer recognizes. Same
failure shape as theMAX_REQSsilent-truncation bug (v0.5.51, issue
#100): incomplete data must never read as complete. Now fails loudly
with a diagnostic note; the report also no longer shows a contradictory
100.00% (0/0 conditions) FAIL.- The branch-coverage MC/DC fallback is now honestly labeled. Without
--mcdc-file, the DAL-A/ASIL-D-required MC/DC gate falls back to
treating 100% branch coverage as a proxy — but the output was labeled
"MC/DC analysis", which is materially misleading: 100% branch/decision
coverage does not establish that every condition within a decision
independently affects its outcome (the entire reason MC/DC exists as a
distinct, stricter metric). Now: a stderrWARNINGwhenever the proxy
is used, the text label changed to "MC/DC gate (branch-coverage
proxy — NOT verified MC/DC)", a machine-readable
"mcdcProxy": {"verified": false, ...}JSON field, and--helptext
spelling out the distinction.
Installation
# Linux (amd64)
curl -Lo cfusa https://github.com/SoundMatt/c-FuSa/releases/download/v0.5.53/cfusa-linux-amd64
chmod +x cfusa && sudo mv cfusa /usr/local/bin/
# macOS (arm64)
curl -Lo cfusa https://github.com/SoundMatt/c-FuSa/releases/download/v0.5.53/cfusa-darwin-arm64
chmod +x cfusa && sudo mv cfusa /usr/local/bin/
# From source
cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --install buildVerify
cfusa version
cfusa qualifyWhat's Changed
- fix: MC/DC gate no longer silently passes on empty parse; branch-proxy honestly labeled by @SoundMatt in #117
- chore: bump v0.5.52 -> v0.5.53 by @SoundMatt in #118
Full Changelog: v0.5.52...v0.5.53
v0.5.52
cfusa v0.5.52
ASIL-scaling initiative (issue #103, sub-issues #104-#109). c-FuSa correctly
derived ASIL but didn't scale the rigor ISO 26262 actually escalates at
higher ASIL levels — MC/DC coverage, independent review/test, and
complexity/rule strictness were either DO-178C-DAL-only or inert metadata.
Checked against both the x-FuSa master spec and its Go reference
implementation (FuSaOps) before starting: neither mandates or implements
this either, so this is c-FuSa leading the tool family, not catching up
to a spec requirement.
Added
- Shared ASIL/DAL severity helper (
include/cfusa/severity.h,
src/severity.c, #104):cfusa_dal_rank(),cfusa_asil_rank(), and
cfusa_required_severity(enforce, dal, asil, &sev)— one canonical
"how strict should this gate be" derivation (an--enforce auto|error|warn|offconvention), modeled on FuSaOps'
trace.SeverityForDecomposition.cmd_safety_rules.c's local
asil_rank()(HARA005) migrated onto it as a proof of the API shape. cfusa qualify --project-asil/--enforce(#105):achievableAsil
is now computed from--implementation-author/--independent-reviewer/
--independent-test-executor(ISO 26262-8 §11 ceiling logic: no
independent reviewer → ASIL-B, reviewer only → ASIL-C, reviewer +
test executor → ASIL-D; self-attestation doesn't count) instead of
accepted as a free-input string, and the command now fails when the
computed ceiling is below a declared--project-asil. Breaking:
removes the previously-inert--achievable-asilflag.cfusa coverage --asil QM|ASIL-A|ASIL-B|ASIL-C|ASIL-D(#106):
ISO 26262-6 Table 12 structural-coverage/MC/DC gate, mirroring--dal's
four-tier shape (ASIL-D requires MC/DC, ASIL-C requires full branch
coverage, ASIL-A/B require full line coverage, QM has no requirement).
When both--daland--asilare given, the stricter of the two
applies to each of line/branch/MC/DC independently.CFUSA-L011/CFUSA-L012lint rules (#108): octal constants
(MISRA-C 2012 Rule 7.1) and macros named the same as a C keyword
(Rule 20.4).cfusa misra's accredited-third-party-tool recommendation
now escalates toREQUIRED(notRECOMMENDED) when the project
declares ISO 26262 ASIL-C/D — the recommendation itself is unchanged,
only its stated strength scales with declared criticality.docs/standards/iso26262.md(#109): command mapping, ASIL
derivation, what scales by ASIL today, and an explicit statement of
what doesn't — no programmatic Tool Confidence Level (TCL, ISO 26262-8
Tables 4-5) determination exists anywhere in c-FuSa (or the wider
x-FuSa family) yet. Every command in its workflow example was run
against a real build before being written down.
Fixed
check's automaticCOMP001gate now recognizes ISO 26262 ASIL
(#107): previously only DO-178C DAL tags in.fusa.json's
standards[]were recognized, so an ISO-26262-only project silently
got the unscaled default complexity threshold instead of the
ASIL-appropriate one (matchingcfusa comp --asil-d/c/b/a's existing
table), unless it separately rancfusa compby hand. When both a DAL
and an ASIL are declared, the stricter threshold wins.
Installation
# Linux (amd64)
curl -Lo cfusa https://github.com/SoundMatt/c-FuSa/releases/download/v0.5.52/cfusa-linux-amd64
chmod +x cfusa && sudo mv cfusa /usr/local/bin/
# macOS (arm64)
curl -Lo cfusa https://github.com/SoundMatt/c-FuSa/releases/download/v0.5.52/cfusa-darwin-arm64
chmod +x cfusa && sudo mv cfusa /usr/local/bin/
# From source
cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --install buildVerify
cfusa version
cfusa qualifyWhat's Changed
- feat: add shared ASIL/DAL required-severity helper by @SoundMatt in #110
- feat: cfusa qualify computes and enforces achievable ASIL from V&V independence by @SoundMatt in #111
- feat: add ASIL-aware MC/DC coverage gate to cfusa coverage by @SoundMatt in #112
- feat: unify complexity threshold between cfusa comp and check's COMP001 by @SoundMatt in #113
- feat: expand MISRA-C rule coverage; ASIL-scale the accredited-tool note by @SoundMatt in #114
- docs: add docs/standards/iso26262.md by @SoundMatt in #115
- chore: bump v0.5.51 -> v0.5.52 by @SoundMatt in #116
Full Changelog: v0.5.51...v0.5.52
v0.5.51
cfusa v0.5.51
Fixes issue #100: silent, uncapped-looking data loss in the three commands
check/CI treat as the safety-traceability source of truth.
Fixed
cmd_req/cmd_trace: silent requirement-catalog truncation
(MAX_REQS)..fusa-reqs.json'srequirementsarray was parsed into a
fixed 1024-entry stack array (g_reqs); the parse loop simply stopped
once it was full, with no error, warning, or truncation notice of any
kind. A project whose requirement catalog grew past 1024 entries got a
false 100% coverage / 0-errors reading fromcfusa trace/cfusa check, because every requirement past the cap was never loaded at all —
it could never be reported missing, untested, or dangling. Reproduced
concretely against a 1075-entry catalog:cfusa tracereported
1024/1024 requirements traced(should be1075/1075), and a real,
correctly-tagged requirement past the cap was flagged as a dangling test
reference despite existing in the file.cmd_impact: same bug,MAX_REQS=256.load_req_ids()capped the
requirement-id list at a fixed 256 entries with the same silent-stop
behavior, so a requirement past the cap could never be matched against
changed files incfusa impact's change-impact analysis.cmd_req/cmd_trace: same bug,MAX_TAGS=4096. The//cfusa:req/
//cfusa:test///cfusa:sec-testannotation array (g_tags) had the
identical fixed-cap/silent-stop pattern. Since a fully-traced requirement
needs at least one (usually two) tags, tag count grows faster than
requirement count — this cap could silently under-report coverage well
before the (now-uncapped) requirements array itself filled up.- All four arrays now grow dynamically via
reallocwith no fixed cap,
bounded only by available memory. A genuine allocation failure (OOM) —
the only way a load can now be incomplete — is reported as a hard
ERRORto stderr with a non-zero exit code, so a truncated run can never
be silently mistaken for a complete one.
Installation
# Linux (amd64)
curl -Lo cfusa https://github.com/SoundMatt/c-FuSa/releases/download/v0.5.51/cfusa-linux-amd64
chmod +x cfusa && sudo mv cfusa /usr/local/bin/
# macOS (arm64)
curl -Lo cfusa https://github.com/SoundMatt/c-FuSa/releases/download/v0.5.51/cfusa-darwin-arm64
chmod +x cfusa && sudo mv cfusa /usr/local/bin/
# From source
cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --install buildVerify
cfusa version
cfusa qualifyWhat's Changed
- fix: remove silent MAX_REQS truncation in cmd_req/cmd_trace/cmd_impact by @SoundMatt in #101
- chore: bump v0.5.50 -> v0.5.51 by @SoundMatt in #102
Full Changelog: v0.5.50...v0.5.51
v0.5.50
cfusa v0.5.50
Renumbered from v0.5.49: the tag/release v0.5.49 had already been
published (2026-07-29, PR #93) against a commit whose version.h still
read "0.5.48" — a pre-existing off-by-one in that release, unrelated to
this change. To avoid re-using an already-shipped version string, this
release is v0.5.50 instead.
External third-party audit remediation. Two of the findings are
live-exploitable command/argument-injection vulnerabilities, independently
reproduced against the shipped tool before being fixed here; the rest are
correctness/robustness defects in the ASIL derivation table, its test
coverage, and several check/trace/report code paths.
Security
impactgit-ref argument injection.cmd_impact.c's--from/--to
validator accepted a value beginning with-and built the underlying
git diffinvocation with no--separator between refs and paths. A
crafted--fromvalue could smuggle an arbitrarygit diffflag —
reproduced concretely withcfusa impact --from '--output=victim.txt' --to HEAD, which truncatesvictim.txtvia git's own--outputflag. Refs
beginning with-are now rejected, and a--separator is always
inserted before the ref arguments. While hardening this path,run_git_diff()
was also moved offpopen()/a shell command string ontofork+execvp
(argv passed directly, no shell), removing the shell entirely rather than
just refusing to abuse it.audit-packshell command injection.cmd_audit_pack.cinterpolated
unsanitized--output/--dirvalues into a double-quoted
system("cd ... && zip ...")string;$(...)command substitution is
still expanded inside double quotes by the shell, so a crafted--output
executed arbitrary commands — reproduced concretely withcfusa audit-pack --output 'x.zip$(touch /tmp/pwned)'. Thesystem()/zip/rm -rfshell
pipeline has been replaced withfork/execvp(argv passed directly, no
shell interpretation) and a POSIXnftw()-based recursive remove for
staging cleanup.
Fixed
- ISO 26262-3:2018 Table 4 ASIL derivation corrected (Critical). The
sharedcfusa_compute_asil()table (src/asil.c) over-assigned ASIL in 19
of 36 S×E×C cells (all S2 except the E1 row, and every S3 row). It now
implements the additive S+E+C mapping (≤6 → QM, 7 → A, 8 → B, 9 → C, 10 →
D).tests/test_asil_table.c's "exhaustive" 36-cell test previously only
assertedexit == 0and never the returned ASIL string, so it passed
against the wrong table; it now asserts the exact ASIL for every cell. The
dogfooded.fusa-hara.jsonshipped over-classified hazard ASILs (H-001
through H-005) as a direct consequence of the table bug and has been
regenerated to match. NOTE: the v0.5.47 entry below described the table as
making both call sites "provably consistent" — they were consistent with
each other but consistently wrong until this fix. - C0 controllability now maps to QM. A non-standard
C0("controllable
in general") value previously fell through to a non-QM result; per ISO
26262-3:2018 §4.3.5 it now short-circuitscfusa_compute_asil()to QM
regardless of S/E. - Out-of-range S/E/C now rejected.
harapreviously coerced an
out-of-range severity/exposure/controllability value to QM silently; it
now exits 2 with a diagnostic instead of masking a malformed hazard entry. - Duplicate requirement ids now fail
check. A duplicateidin
.fusa-reqs.json/.cfusa-reqs.jsonwas previously only reported as a
cfusa trace: ERROR: ...line on stderr, never as a machine-readable
Finding, and never affected any command's exit code. A newcheck
engine rule,DUPREQ001, re-parses the requirements registry and emits a
real, fingerprinted §4 Finding (SEV_ERROR) for each duplicated id, so
cfusa checknow fails on it. tracereads the canonicalparentkey.cmd_trace.cread only the
legacyparentIdfield for LLR→HLR links; it now reads the spec-canonical
parentkey first, falling back toparentIdfor backward compatibility.- Report envelope no longer hardcodes an always-empty
errorsarray.
src/report.cemitted a permanently-empty"errors": []array in every
report; per the x-FuSa spec this MUST be a singularerror{code,message}
object present only when a runtime error occurred (and omitted
otherwise), which is now what's emitted. ftell()return value now bounds-checked.cfusa_read_file()
(src/utils.c) used an uncheckedftell()result as an allocation size;
on a crafted or unseekable file this could wrap to a huge or negative
value and cause a heap-overflow/DoS. The result is now validated before
use.- Requirement objects over 1KB no longer truncated.
cmd_trace.c
parsed each requirement object into a fixed 1024-byte stack buffer,
silently droppingid/title/parentfields past that size; it now
heap-allocates to the exact object length. .fusa.jsonversion string reconciled.project.versionhad drifted
to a stale"0.5.1"while the shipped tool moved well past it; it now
matches the real released version. (The README's config-name guidance was
also updated to point at the canonical.fusa-*names rather than the
deprecated.cfusa-*ones, with the legacy names kept as a documented
fallback; a version badge was added to README so the new
version-consistency CI check has something real to verify against.)cfusa checknow passes cleanly on c-FuSa's own source (previously
masked by|| truein CI — see Changed, below — so this had silently
regressed):cmd_qualify.c's pre-existingqt_rmdir_recursive()and the
newcmd_audit_pack.cap_rmdir_recursive()both used genuine user-code
recursion (MISRA-C 2012 Rule 17.2,CFUSA-L004); both are now iterative,
built on POSIXnftw(FTW_DEPTH|FTW_PHYS).cmd_comp.chad two lines each
freeing two distinct pointers, which a same-line text scan mistook for a
double-free (CFUSA-CY007); the frees are now on separate lines. Two test
function names —..._includes_end_lineand..._no_build_system—
coincidentally contained the substringsdes_andsystem(, false-firing
the weak-crypto and unchecked-system-call rules (CFUSA-CY009/CY003);
both were renamed.cmd_req.c's ALM-import entry builder hardened against unbounded
write.append_entry()(used byreq importfor CSV/ReqIF/XML sources)
tracked the destination buffer's fill level via a caller-passed running
total rather than the buffer's actual content length, and appended with
strcat(). GitHub Advanced Security's CodeQL flagged this as a possible
unbounded write fromfgets/fread-sourced input (critical). It's
rewritten to measure the buffer's real length directly and append with an
exact-lengthmemcpy()bounded against that, removing the dependency on
the caller's bookkeeping entirely.
Changed
qualify's qualification timestamp now honoursSOURCE_DATE_EPOCHfor
reproducible builds.- CI (
ci.yml) no longer masks 5 meaningful steps behind|| true,
including the version-consistency check, which now actually fails the
build on drift. Theiso26262gap-report step is intentionally left
informational (|| true): it exits 1 whenever any §9.3 gap remains by
design, and closing every long-standing documentation/process gap (e.g.
"functional safety concept", "no multiple exit points") is a separate,
much larger effort than this release's scope. The Docker self-check step
now checks the whole mounted repo (--dir /workspace) instead of just
/workspace/src, matching the native self-check step —src/alone can
never contain the root-level.fusa.json/.fusa-hara.json, so scoping to
it madeFUSA00x/HARA001fail unconditionally the moment this step's
exit code started being enforced. docker-publish.yml's runner is pinned toubuntu-22.04for
build-environment parity/reproducibility.
Removed
- The stale committed
.cfusa_qualification.json(wrong version, obsolete
schema) has been deleted; CI regenerates it as a build artifact instead of
it being tracked in source control.
Installation
# Linux (amd64)
curl -Lo cfusa https://github.com/SoundMatt/c-FuSa/releases/download/v0.5.50/cfusa-linux-amd64
chmod +x cfusa && sudo mv cfusa /usr/local/bin/
# macOS (arm64)
curl -Lo cfusa https://github.com/SoundMatt/c-FuSa/releases/download/v0.5.50/cfusa-darwin-arm64
chmod +x cfusa && sudo mv cfusa /usr/local/bin/
# From source
cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --install buildVerify
cfusa version
cfusa qualifyWhat's Changed
- fix: v0.5.49 — ASIL Table 4 correction + two live-exploitable injection fixes by @SoundMatt in #95
- chore: renumber v0.5.49 -> v0.5.50 (version string collision) by @SoundMatt in #96
Full Changelog: v0.5.49...v0.5.50
v0.5.49
cfusa v0.5.49
No CHANGELOG.md entry found for this release — see commit history.
Installation
# Linux (amd64)
curl -Lo cfusa https://github.com/SoundMatt/c-FuSa/releases/download/v0.5.49/cfusa-linux-amd64
chmod +x cfusa && sudo mv cfusa /usr/local/bin/
# macOS (arm64)
curl -Lo cfusa https://github.com/SoundMatt/c-FuSa/releases/download/v0.5.49/cfusa-darwin-arm64
chmod +x cfusa && sudo mv cfusa /usr/local/bin/
# From source
cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --install buildVerify
cfusa version
cfusa qualifyWhat's Changed
- chore: pin x-FuSa spec version to v1.15.2 by @SoundMatt in #93
Full Changelog: v0.5.48...v0.5.49
v0.5.48
cfusa v0.5.48
No CHANGELOG.md entry found for this release — see commit history.
Installation
# Linux (amd64)
curl -Lo cfusa https://github.com/SoundMatt/c-FuSa/releases/download/v0.5.48/cfusa-linux-amd64
chmod +x cfusa && sudo mv cfusa /usr/local/bin/
# macOS (arm64)
curl -Lo cfusa https://github.com/SoundMatt/c-FuSa/releases/download/v0.5.48/cfusa-darwin-arm64
chmod +x cfusa && sudo mv cfusa /usr/local/bin/
# From source
cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --install buildVerify
cfusa version
cfusa qualifyWhat's Changed
- fix: 2026-07-28 deep-audit bug-fix sprint (issues #82-91) by @SoundMatt in #92
Full Changelog: v0.5.47...v0.5.48