Skip to content

Commit 471cfec

Browse files
committed
fix: fusa-asil-b CI gate — pin cpp-FuSa v0.17.1, stop wiping requirements, enforce real gap thresholds
Three compounding problems in the fusa-asil-b (and sarif) CI jobs: 1. cpp-FuSa was pinned to v0.15.0, missing conformance fixes through v0.17.1 that affect this repo's own generated evidence (sbom.json component hashes, safety-case completeness — see cpp-FuSa's CHANGELOG v0.17.0 entry). Both jobs now pin v0.17.1. 2. `cpfusa init --force` ran as the first step in both jobs, before the traceability step, unconditionally overwriting the real, populated `.fusa-reqs.json` (50+ KB of hand-maintained REQ-* entries) with an empty scaffold. CI traceability coverage was always computed against zero requirements regardless of the repo's actual state. Removed the step entirely — `.fusa.json`/`.fusa-reqs.json` are already checked in and match what `init` would have generated; the step is only needed for first-time local setup. 3. The ISO 26262 / IEC 61508 gap-analysis steps were wrapped in `|| true`, so they could never fail the build regardless of gap count (15/20 and 12/18 gaps at last real measurement). Two changes: - Reordered the job so boundary/tara/fmea/safety-case/sas/sci run BEFORE the gap analyses: cpfusa grades several objectives (e.g. §9-2.1 Safety case, §10.4 SCI) on whether safety-case.json/ sci.json already exist, so gap-checking first was undercounting what the repo actually addresses. This alone closed 2 gaps. - Replaced `|| true` with an explicit, intentional gate: fail the build if the gap count regresses past the current, documented baseline (13 for ISO 26262, 11 for IEC 61508). A "0 gaps" target is not reachable with cpfusa v0.17.1 regardless of this repo's actual documentation completeness — several objectives (e.g. §6.1 Software architectural design, §8-6.2 Safety manual) have no evidence-detection logic implemented in the tool at all and report Gap unconditionally (cpp-FuSa src/iso26262/iso26262.cpp's detect_status()). The gate at least makes future regressions visible instead of being structurally unable to fail. Also fixed independently while investigating (2), a real bug the fix exposed: cpp-FuSa v0.17.0 started actually enforcing `sourceDirs` (previously ignored per its own CHANGELOG), and `.fusa.json`'s sourceDirs (["src", "include"]) omitted "tests" and "cli" — so every `fusa:test`/`fusa:req` annotation in those directories silently stopped being seen by `trace`, dropping real test-coverage traceability from 93.5% to 0% the moment the pin bumped. Added both directories to sourceDirs, and registered 6 real, already-annotated CLI requirements (REQ-CLI-001..006, both impl- and test-annotated in cli/ and tests/test_cli.cpp already) that this surfaced as dangling references in requirements/requirements.json and .fusa-reqs.json. README's ASIL-B badge/description is reworded to "ASIL-B target (SEooC)" with a pointer to the real gap-report artifacts, per this repo's own SAFETY_PLAN.md framing — the prior flat "ISO 26262 ASIL-B" claim overstated completeness relative to the tool's own (now enforced) gap reports. Verified locally end-to-end against a clean checkout with a freshly built cpfusa v0.17.1: check/lint/trace/cyber/qualify/boundary/tara/ fmea/safety-case/sas/sci/badge/vuln/metrics/report all exit 0; trace reports 135/144 (93.8%) annotated and tested with zero dangling references; iso26262 gate passes at 13 gaps (baseline); iec61508 gate passes at 10 gaps (under the 11 baseline). Closes #19, #20, #21 Signed-off-by: Matt <47545907+SoundMatt@users.noreply.github.com>
1 parent b2480f4 commit 471cfec

5 files changed

Lines changed: 125 additions & 27 deletions

File tree

.fusa-reqs.json

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,54 @@
609609
"rationale": "Slaves must be able to update responses (e.g., refreshed sensor values) without removing and re-registering.",
610610
"tags": ["slave", "update"]
611611
},
612+
{
613+
"id": "REQ-CLI-001",
614+
"title": "version command reports tool/protocol/spec_version fields",
615+
"description": "cmd_version's json and text renderings shall include tool, protocol, version, spec_version, language, and runtime fields per RELAY spec §12.1.",
616+
"asil": "ASIL-B",
617+
"rationale": "Integrators must be able to programmatically confirm which cpp-lin build and RELAY spec version a binary implements.",
618+
"tags": ["cli"]
619+
},
620+
{
621+
"id": "REQ-CLI-002",
622+
"title": "capabilities command reports transports/features/interfaces",
623+
"description": "capabilities_json() shall report kind, tool, protocol, version, spec_version, commands, transports, features, interfaces, optional_interfaces, and adapt per RELAY spec §12.2.",
624+
"asil": "ASIL-B",
625+
"rationale": "Downstream tooling (e.g. relay conform) discovers a binary's supported feature set from this document.",
626+
"tags": ["cli"]
627+
},
628+
{
629+
"id": "REQ-CLI-003",
630+
"title": "status command reports health/connection fields",
631+
"description": "cmd_status's json and text renderings shall include protocol, tool, version, healthy, connected, endpoint, and details fields per RELAY spec §12.3.",
632+
"asil": "ASIL-B",
633+
"rationale": "Operators and orchestration tooling need a machine-readable liveness/health signal.",
634+
"tags": ["cli"]
635+
},
636+
{
637+
"id": "REQ-CLI-004",
638+
"title": "parse_frame_json parses a LIN frame from JSON",
639+
"description": "parse_frame_json shall extract id, data, checksum_type, and checksum from a JSON object and throw on a missing or invalid id field.",
640+
"asil": "ASIL-B",
641+
"rationale": "The CLI's frame-publish path depends on correctly reconstructing a lin::Frame from user-supplied JSON.",
642+
"tags": ["cli", "json"]
643+
},
644+
{
645+
"id": "REQ-CLI-005",
646+
"title": "message_to_json serialises a RELAY Message to JSON",
647+
"description": "message_to_json shall serialise protocol, version, id, base64 payload, timestamp, and (when present) seq/meta fields.",
648+
"asil": "ASIL-B",
649+
"rationale": "relay conform and downstream consumers depend on a spec-conformant JSON rendering of RELAY messages.",
650+
"tags": ["cli", "json"]
651+
},
652+
{
653+
"id": "REQ-CLI-006",
654+
"title": "convert command rejects RELAY error-vector inputs per spec",
655+
"description": "cmd_convert (and the underlying conversion path) shall reject inputs matching RELAY's published error vectors (e.g. ID overflow, wrong checksum) rather than silently accepting them.",
656+
"asil": "ASIL-B",
657+
"rationale": "RELAY spec §20 continuous conformance requires a conformant implementation to exercise the reject path, not only the happy path.",
658+
"tags": ["cli", "conformance"]
659+
},
612660
{
613661
"id": "REQ-SAFETY-001",
614662
"title": "DataID embedded in header bytes 0-1",

.fusa.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
},
88
"sourceDirs": [
99
"src",
10-
"include"
10+
"include",
11+
"tests",
12+
"cli"
1113
],
1214
"standard": "iso26262",
1315
"strict": false

.github/workflows/ci.yml

Lines changed: 58 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ jobs:
234234
with:
235235
repository: SoundMatt/cpp-FuSa
236236
path: cpp-FuSa
237-
ref: v0.15.0
237+
ref: v0.17.1
238238

239239
- name: Install tools
240240
run: sudo apt-get update -qq && sudo apt-get install -y cmake ninja-build zip
@@ -247,9 +247,13 @@ jobs:
247247
-G Ninja
248248
cmake --build cpp-FuSa/build --parallel
249249
250-
- name: cpfusa init
251-
working-directory: cpp-LIN
252-
run: ../cpp-FuSa/build/cpfusa init --name cpp-LIN --standard iso26262 --asil ASIL-B --project-version 0.4.0 --force || true
250+
# No `cpfusa init` step: .fusa.json and .fusa-reqs.json are real,
251+
# populated, checked-in files (the latter is 50+ KB of hand-maintained
252+
# REQ-* entries). `init --force` unconditionally overwrote both with
253+
# an empty scaffold before the traceability step ever ran, so CI's
254+
# requirements coverage was always computed against zero requirements
255+
# regardless of the repo's real state (cpp-LIN#19). `init` is only
256+
# needed for first-time local setup, where these files don't exist yet.
253257

254258
- name: cpfusa check
255259
working-directory: cpp-LIN
@@ -275,22 +279,12 @@ jobs:
275279
working-directory: cpp-LIN
276280
run: ../cpp-FuSa/build/cpfusa hara init --project cpp-LIN --dir . || true
277281

278-
- name: cpfusa iso26262 (ASIL-B)
279-
working-directory: cpp-LIN
280-
run: |
281-
../cpp-FuSa/build/cpfusa iso26262 \
282-
--asil ASIL-B \
283-
--output iso26262-gap-report.json \
284-
--dir . || true
285-
286-
- name: cpfusa iec61508 (SIL-2)
287-
working-directory: cpp-LIN
288-
run: |
289-
../cpp-FuSa/build/cpfusa iec61508 \
290-
--sil SIL-2 \
291-
--output iec61508-gap-report.json \
292-
--dir . || true
293-
282+
# boundary/tara/fmea/safety-case/sas/sci run BEFORE the iso26262/
283+
# iec61508 gap analyses below: several ISO 26262/IEC 61508 objectives
284+
# (e.g. §9-2.1 Safety case, §10.4 SCI) are graded by cpfusa on whether
285+
# safety-case.json/sci.json etc. already exist on disk. Gap-checking
286+
# before generating them undercounted objectives this repo actually
287+
# addresses.
294288
- name: cpfusa boundary
295289
working-directory: cpp-LIN
296290
run: ../cpp-FuSa/build/cpfusa boundary --dir .
@@ -315,6 +309,47 @@ jobs:
315309
working-directory: cpp-LIN
316310
run: ../cpp-FuSa/build/cpfusa sci --dir .
317311

312+
# These gates enforce a documented, currently-achieved baseline gap
313+
# count rather than requiring zero gaps outright: cpfusa v0.17.1 has
314+
# no evidence-detection logic at all for several objectives (e.g. §6.1
315+
# Software architectural design, §8-6.2 Safety manual — see cpp-FuSa
316+
# src/iso26262/iso26262.cpp's detect_status(), which falls through to
317+
# Status::Gap unconditionally for those IDs regardless of what evidence
318+
# exists), so a "0 gaps" target is not achievable with this tool
319+
# version no matter how complete this repo's safety documentation is.
320+
# The gate below still turns this into a real, enforced check: it
321+
# fails the build if the gap count *regresses* past the current
322+
# baseline, rather than being structurally unable to fail at all
323+
# (cpp-LIN#20). See SAFETY_PLAN.md for this repo's ASIL-B *target*
324+
# framing (SEooC, not a completed-certification claim).
325+
- name: cpfusa iso26262 (ASIL-B)
326+
working-directory: cpp-LIN
327+
run: |
328+
../cpp-FuSa/build/cpfusa iso26262 \
329+
--asil ASIL-B \
330+
--output iso26262-gap-report.json \
331+
--dir .
332+
GAPS=$(jq '.summary.gaps' iso26262-gap-report.json)
333+
echo "ISO 26262 gaps: ${GAPS} (baseline: 13)"
334+
if [ "${GAPS}" -gt 13 ]; then
335+
echo "::error::ISO 26262 gap count ${GAPS} exceeds baseline of 13 — see iso26262-gap-report.json"
336+
exit 1
337+
fi
338+
339+
- name: cpfusa iec61508 (SIL-2)
340+
working-directory: cpp-LIN
341+
run: |
342+
../cpp-FuSa/build/cpfusa iec61508 \
343+
--sil SIL-2 \
344+
--output iec61508-gap-report.json \
345+
--dir .
346+
GAPS=$(jq '.summary.gaps' iec61508-gap-report.json)
347+
echo "IEC 61508 gaps: ${GAPS} (baseline: 11)"
348+
if [ "${GAPS}" -gt 11 ]; then
349+
echo "::error::IEC 61508 gap count ${GAPS} exceeds baseline of 11 — see iec61508-gap-report.json"
350+
exit 1
351+
fi
352+
318353
- name: cpfusa badge
319354
working-directory: cpp-LIN
320355
run: ../cpp-FuSa/build/cpfusa badge --dir .
@@ -435,7 +470,7 @@ jobs:
435470
with:
436471
repository: SoundMatt/cpp-FuSa
437472
path: cpp-FuSa
438-
ref: v0.15.0
473+
ref: v0.17.1
439474

440475
- name: Install tools
441476
run: sudo apt-get update -qq && sudo apt-get install -y cmake ninja-build
@@ -448,9 +483,8 @@ jobs:
448483
-G Ninja
449484
cmake --build cpp-FuSa/build --parallel
450485
451-
- name: cpfusa init
452-
working-directory: cpp-LIN
453-
run: ../cpp-FuSa/build/cpfusa init --name cpp-LIN --standard iso26262 --asil ASIL-B --project-version 0.4.0 --force || true
486+
# No `cpfusa init` step here either — see the fusa-asil-b job's note
487+
# (cpp-LIN#19): .fusa.json/.fusa-reqs.json are already checked in.
454488

455489
- name: Generate SARIF report
456490
working-directory: cpp-LIN

README.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
# cpp-LIN
22

3-
C++ LIN bus library — RELAY-conformant, ISO 26262 ASIL-B.
3+
C++ LIN bus library — RELAY-conformant, ISO 26262 ASIL-B target (SEooC).
44

55
[![CI](https://github.com/SoundMatt/cpp-LIN/actions/workflows/ci.yml/badge.svg)](https://github.com/SoundMatt/cpp-LIN/actions/workflows/ci.yml)
66
[![RELAY Conformant](https://img.shields.io/badge/RELAY-v1.11%20conformant-blue)](https://github.com/SoundMatt/RELAY)
7-
[![ASIL-B](https://img.shields.io/badge/ISO%2026262-ASIL--B-orange)](SAFETY_PLAN.md)
7+
[![ASIL-B target](https://img.shields.io/badge/ISO%2026262-ASIL--B%20target-yellow)](SAFETY_PLAN.md)
88
[![License: MPL 2.0](https://img.shields.io/badge/License-MPL%202.0-brightgreen.svg)](LICENSE)
99

10+
cpp-LIN is a Safety Element out of Context (SEooC, ISO 26262-10 §9) targeting
11+
ASIL-B, not a completed third-party certification. CI runs `cpfusa iso26262`/
12+
`cpfusa iec61508` gap analyses on every build and gates on non-regression
13+
against a documented baseline (`.github/workflows/ci.yml`'s `fusa-asil-b`
14+
job); see `iso26262-gap-report.json`/`iec61508-gap-report.json` in that job's
15+
uploaded evidence artifacts for the current, honest gap count rather than
16+
treating the badge above as a completeness claim.
17+
1018
## Overview
1119

1220
cpp-LIN is a production-quality C++ implementation of the LIN (Local Interconnect

requirements/requirements.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@
8484
{"id": "REQ-SLAVE-006", "title": "subscribe delegates to bus", "asil": "ASIL-B", "tags": ["slave"]},
8585
{"id": "REQ-SLAVE-007", "title": "registered_ids returns empty slice when none", "asil": "ASIL-B", "tags": ["slave", "boundary"]},
8686
{"id": "REQ-SLAVE-008", "title": "set_response overwrites previous registration", "asil": "ASIL-B", "tags": ["slave", "update"]},
87+
{"id": "REQ-CLI-001", "title": "version command reports tool/protocol/spec_version fields", "asil": "ASIL-B", "tags": ["cli"]},
88+
{"id": "REQ-CLI-002", "title": "capabilities command reports transports/features/interfaces", "asil": "ASIL-B", "tags": ["cli"]},
89+
{"id": "REQ-CLI-003", "title": "status command reports health/connection fields", "asil": "ASIL-B", "tags": ["cli"]},
90+
{"id": "REQ-CLI-004", "title": "parse_frame_json parses a LIN frame from JSON", "asil": "ASIL-B", "tags": ["cli", "json"]},
91+
{"id": "REQ-CLI-005", "title": "message_to_json serialises a RELAY Message to JSON", "asil": "ASIL-B", "tags": ["cli", "json"]},
92+
{"id": "REQ-CLI-006", "title": "convert command rejects RELAY error-vector inputs per spec", "asil": "ASIL-B", "tags": ["cli", "conformance"]},
8793
{"id": "REQ-SAFETY-001", "title": "DataID embedded in header bytes 0-1", "asil": "ASIL-B", "tags": ["safety", "header"]},
8894
{"id": "REQ-SAFETY-002", "title": "SourceID embedded in header bytes 2-3", "asil": "ASIL-B", "tags": ["safety", "header"]},
8995
{"id": "REQ-SAFETY-003", "title": "SequenceCounter starts at 0 and increments", "asil": "ASIL-B", "tags": ["safety", "counter"]},

0 commit comments

Comments
 (0)