Skip to content

Releases: SoundMatt/c-FuSa

v0.6.2

Choose a tag to compare

@github-actions github-actions released this 18 Aug 23:22
c836a68

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 independent cfusa_walk_sources() call sites (one per
    rule) into one walk-and-dispatch pass per cfusa check/lint/
    analyze/cyber run. (#204)
  • #if 0 preprocessor-lite awareness — code inside an
    unconditionally-disabled #if 0 block is no longer scanned by
    line-based rules, removing a class of false positives on intentionally
    dead/documentation code. (#205)
  • cfusa baseline and .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> (via git 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 fix remediation-guidance coverage expanded from 19 to the
    full 39 lint/analyze/cyber rules
    , plus a real --dry-run/--apply
    auto-rewrite for CFUSA-CY006 (free-without-NULL) — conservatively
    scoped to a bare free(<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> (and cfusa 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 missing CFUSA- prefix. (#212)
  • A first-party GitHub Action (action.yml, usable as uses: SoundMatt/c-FuSa@<tag>) — installs a pinned cfusa release binary,
    runs cfusa check, and uploads SARIF to the code-scanning tab, with
    dir/version/strict/changed-since/fail-on-error inputs.
    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), the opendir()/readdir()-based tree walk underlying every
    rule, and getopt_long (all 44 cmd_*.c files) have no direct Windows
    equivalent — this is a systemic, cross-cutting port, not a bounded
    feature. WSL2 already runs today's cfusa unmodified 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 build

Verify

cfusa version
cfusa qualify

What'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

Choose a tag to compare

@github-actions github-actions released this 18 Aug 20:31
2e0f3c2

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 add wasn'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_root wasn'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.c resolved the wrong requirements filename in some code
    paths, --sec-tested didn't gate on the real tested count, and
    Metric 1 could disagree with the underlying data.
    Canonical
    .fusa-reqs.json resolution with legacy fallback; a real
    --sec-tested gate. (#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's strncpy could leave an unterminated buffer; L002 only matched
    goto when 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 and cfusa_config_is_excluded() matched
    substrings without boundary checks
    , e.g. excluding src/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.c had 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 —
    reordering operationalSituations/hazards/safetyGoals in 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-D silently discarded an explicit --threshold
    (zeroing it instead of leaving it alone, asymmetric with how
    --asil QM already 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_long loops fully reset BSD's
    optreset/glibc's nextchar
    between invocations — a bare
    optind = 1 doesn'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 hardcoded return 0
    regardless of findings added,
    breaking the run()-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 build

Verify

cfusa version
cfusa qualify

What'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

Choose a tag to compare

@github-actions github-actions released this 18 Aug 13:03
b31de6c

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's qualified/qualificationBadge JSON fields could
    disagree
    (qualified: true next to qualificationBadge: "unqualified") since they were computed independently. qualified now
    requires both passing self-tests AND a declared --qualification-method.
    (#128)
  • cmd_hara.c's split_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-case hardcoded exact lowercase evidence filenames
    (hara.md, safety-plan.md, etc.), case-sensitive via stat() — 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-file parsed a schema that never matched real
    llvm-cov export output
    , so every genuine export reported 0 MC/DC
    conditions. Fixed and verified against an actual captured llvm-cov export run (both a fully-covered and zero-covered case). (#129)

Added

  • cfusa fix remediation 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:req tag directly above the
    function's own definition), additive alongside the unchanged file-level
    --func-coverage. (#125)
  • .fusa-dispositions.json is now enforced, not just logged.
    cfusa check/cfusa lint load 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 build

Verify

cfusa version
cfusa qualify

What'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

Choose a tag to compare

@github-actions github-actions released this 14 Aug 16:57
ee91bac

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 via TEST_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_ERROR instead of the uniform SEV_WARNING every project got before.
    Shared cfusa_declared_asil_rank() (moved from a cmd_misra.c-local
    helper into severity.h) so this and the accredited-tool note (v0.5.52)
    don't drift independently.

Logged, not yet built

  • Issue #122: wire .fusa-dispositions.json into cfusa 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 build

Verify

cfusa version
cfusa qualify

What'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

Choose a tag to compare

@github-actions github-actions released this 14 Aug 12:35
ea81009

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-file no 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 the MAX_REQS silent-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 stderr WARNING whenever 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 --help text
    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 build

Verify

cfusa version
cfusa qualify

What'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

Choose a tag to compare

@github-actions github-actions released this 13 Aug 23:27
5a5610a

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|off convention), 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-asil flag.
  • 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 --dal and --asil are given, the stricter of the two
    applies to each of line/branch/MC/DC independently.
  • CFUSA-L011/CFUSA-L012 lint 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 to REQUIRED (not RECOMMENDED) 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 automatic COMP001 gate 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 (matching cfusa comp --asil-d/c/b/a's existing
    table), unless it separately ran cfusa comp by 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 build

Verify

cfusa version
cfusa qualify

What'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

Choose a tag to compare

@github-actions github-actions released this 13 Aug 21:34
82a9ff3

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's requirements array 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 from cfusa 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 trace reported
    1024/1024 requirements traced (should be 1075/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 in cfusa impact's change-impact analysis.
  • cmd_req/cmd_trace: same bug, MAX_TAGS=4096. The //cfusa:req/
    //cfusa:test///cfusa:sec-test annotation 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 realloc with 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
    ERROR to 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 build

Verify

cfusa version
cfusa qualify

What'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

Choose a tag to compare

@github-actions github-actions released this 30 Jul 20:27
12a30f4

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

  • impact git-ref argument injection. cmd_impact.c's --from/--to
    validator accepted a value beginning with - and built the underlying
    git diff invocation with no -- separator between refs and paths. A
    crafted --from value could smuggle an arbitrary git diff flag —
    reproduced concretely with cfusa impact --from '--output=victim.txt' --to HEAD, which truncates victim.txt via git's own --output flag. 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 off popen()/a shell command string onto fork+execvp
    (argv passed directly, no shell), removing the shell entirely rather than
    just refusing to abuse it.
  • audit-pack shell command injection. cmd_audit_pack.c interpolated
    unsanitized --output/--dir values 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 with cfusa audit-pack --output 'x.zip$(touch /tmp/pwned)'. The system()/zip/rm -rf shell
    pipeline has been replaced with fork/execvp (argv passed directly, no
    shell interpretation) and a POSIX nftw()-based recursive remove for
    staging cleanup.

Fixed

  • ISO 26262-3:2018 Table 4 ASIL derivation corrected (Critical). The
    shared cfusa_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
    asserted exit == 0 and 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.json shipped 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-circuits cfusa_compute_asil() to QM
    regardless of S/E.
  • Out-of-range S/E/C now rejected. hara previously 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 duplicate id in
    .fusa-reqs.json/.cfusa-reqs.json was 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 new check
    engine rule, DUPREQ001, re-parses the requirements registry and emits a
    real, fingerprinted §4 Finding (SEV_ERROR) for each duplicated id, so
    cfusa check now fails on it.
  • trace reads the canonical parent key. cmd_trace.c read only the
    legacy parentId field for LLR→HLR links; it now reads the spec-canonical
    parent key first, falling back to parentId for backward compatibility.
  • Report envelope no longer hardcodes an always-empty errors array.
    src/report.c emitted a permanently-empty "errors": [] array in every
    report; per the x-FuSa spec this MUST be a singular error{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 unchecked ftell() 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 dropping id/title/parent fields past that size; it now
    heap-allocates to the exact object length.
  • .fusa.json version string reconciled. project.version had 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 check now passes cleanly on c-FuSa's own source (previously
    masked by || true in CI — see Changed, below — so this had silently
    regressed): cmd_qualify.c's pre-existing qt_rmdir_recursive() and the
    new cmd_audit_pack.c ap_rmdir_recursive() both used genuine user-code
    recursion (MISRA-C 2012 Rule 17.2, CFUSA-L004); both are now iterative,
    built on POSIX nftw(FTW_DEPTH|FTW_PHYS). cmd_comp.c had 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_line and ..._no_build_system —
    coincidentally contained the substrings des_ and system(, 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 by req import for 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 from fgets/fread-sourced input (critical). It's
    rewritten to measure the buffer's real length directly and append with an
    exact-length memcpy() bounded against that, removing the dependency on
    the caller's bookkeeping entirely.

Changed

  • qualify's qualification timestamp now honours SOURCE_DATE_EPOCH for
    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. The iso26262 gap-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 made FUSA00x/HARA001 fail unconditionally the moment this step's
    exit code started being enforced.
  • docker-publish.yml's runner is pinned to ubuntu-22.04 for
    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 build

Verify

cfusa version
cfusa qualify

What'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

Choose a tag to compare

@github-actions github-actions released this 29 Jul 04:45
91b3d3c

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 build

Verify

cfusa version
cfusa qualify

What's Changed

Full Changelog: v0.5.48...v0.5.49

v0.5.48

Choose a tag to compare

@github-actions github-actions released this 29 Jul 03:43
0fe2ffb

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 build

Verify

cfusa version
cfusa qualify

What'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