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
3 changes: 3 additions & 0 deletions .fusa-dispositions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"dispositions": []
}
1 change: 1 addition & 0 deletions .fusa.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"version": "1",
"project": {
"name": "cpp-RCP",
"version": "2.26.0",
"module": "github.com/SoundMatt/cpp-RCP",
"standard": "iso26262",
"asil": "ASIL-B"
Expand Down
86 changes: 84 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,39 @@ jobs:
name: compile-commands
path: build/compile_commands.json

# ── Version sources agree ────────────────────────────────────────────────────
# Ported from c-RCP's own version-sources-agree job, adapted for cpp-RCP's
# real version.hpp syntax: c-RCP's version.h uses a preprocessor
# `#define RCP_VERSION "X.Y.Z"`, while cpp-RCP's version.hpp (this being a
# C++17 header-only port) instead declares a
# `constexpr std::string_view kVersion = "X.Y.Z";`, so the grep pattern
# below matches that syntax rather than c-RCP's #define form.
version-sources-agree:
name: CMakeLists.txt / version.hpp / .fusa.json versions agree
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Compare the three version sources
run: |
cmake_version=$(grep -m1 -oE '^\s*VERSION [0-9]+\.[0-9]+\.[0-9]+' CMakeLists.txt | awk '{print $2}')
header_version=$(grep -m1 -oE 'kVersion[[:space:]]*=[[:space:]]*"[0-9]+\.[0-9]+\.[0-9]+"' include/rcp/version.hpp | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
fusa_version=$(grep -m1 -oE '"version": *"[0-9]+\.[0-9]+\.[0-9]+"' .fusa.json | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')

echo "CMakeLists.txt project() VERSION : ${cmake_version:-<not found>}"
echo "include/rcp/version.hpp kVersion : ${header_version:-<not found>}"
echo ".fusa.json \"version\" : ${fusa_version:-<not found>}"

fail=0
[ -n "$cmake_version" ] || { echo "::error file=CMakeLists.txt::Could not parse project() VERSION"; fail=1; }
[ -n "$header_version" ] || { echo "::error file=include/rcp/version.hpp::Could not parse kVersion"; fail=1; }
[ -n "$fusa_version" ] || { echo "::error file=.fusa.json::Could not parse \"version\""; fail=1; }
[ "$fail" -eq 0 ] || exit 1

if [ "$cmake_version" != "$header_version" ] || [ "$cmake_version" != "$fusa_version" ]; then
echo "::error::Version sources disagree -- CMakeLists.txt=$cmake_version, version.hpp=$header_version, .fusa.json=$fusa_version. Bump all three together (see version.hpp's header comment); a mismatch here silently mislabels every SBOM/provenance/compliance-report artifact release.yml generates from .fusa.json's stale value."
exit 1
fi

# ── TLA+ formal verification (TLC model checking) ────────────────────────────
# Independent of the C++ build (tla/*.tla model the safety-relevant state
# machines rcp/lifecycle.hpp and rcp/e2e.hpp implement, not the C++ code
Expand Down Expand Up @@ -677,12 +710,61 @@ jobs:
- name: Build
run: cmake --build build --parallel

# Real root cause of the `|| true` this replaces: `cpfusa analyze`
# (both its clang-tidy and cppcheck integrations) recursively scans
# whatever directory tree it is pointed at with no awareness of
# .fusa.json's excludePatterns. Left as `build/`, that tree contains
# Catch2's own vendored source (FetchContent-populated
# build/_deps/catch2-src/), including Catch2's own SelfTest suite —
# cppcheck chokes on that third-party test code's BDD macros
# (SECTION/GIVEN/CHECKED_IF/...) and reports them as first-party
# ERROR findings (e.g. "unknownMacro", intentional ODR violations in
# Catch2's own test fixtures), which is what was actually keeping this
# job red, not a real defect in cpp-RCP's own code. Separately,
# `cpfusa analyze` looks for compile_commands.json directly under the
# directory it scans (the repo root here) — since it was left inside
# build/ with no copy at the root, clang-tidy has never actually run
# in this job at all (silently falling back to its
# "compile_commands.json not found" info finding).
#
# Fixed by copying compile_commands.json to the root (so clang-tidy
# finally runs for real) and then deleting build/ (and the vendored
# sources inside it) before invoking analyze, so the scan only ever
# sees this project's own first-party sources. With both fixed,
# cpp-RCP's own code has 0 ERROR-severity findings, so this can be a
# real, ungated `|| true`-free hard gate.
- name: Isolate compile_commands.json from vendored build tree
run: |
cp build/compile_commands.json .
rm -rf build

- name: Static analysis
run: /tmp/cpfusa/build/cpfusa analyze || true
run: /tmp/cpfusa/build/cpfusa analyze

# ── cpp-FuSa: 20 CWE-mapped cybersecurity rules (ISO 21434) ─────────────────
# Job renamed from its previous "cpfusa cyber --strict" name, which never
# matched its `run:` line below (plain `cpfusa cyber`, no --strict). --strict
# is a real flag (`cpfusa cyber --help`: "Exit 1 on warnings too"), but
# cpp-RCP does not cleanly pass under it today: a real run surfaces 838
# WARNING-severity findings (613 CYBER009 "integer narrowing conversion",
# 189 CYBER017 "hardcoded IP address", plus smaller CYBER004/012/019
# counts), overwhelmingly the expected, reviewed shape of a wire-protocol
# library (masking/shifting a wider integer down to a byte for
# serialization, and loopback/RFC5737 test addresses in the test suite) —
# not defects, but also not sites that can be responsibly mass-remediated
# or blanket-waived in this batch. Critically, `.fusa-dispositions.json`
# cannot fix this either way: unlike gated_exit_code() (used by
# check/lint/analyze), the `cyber` subcommand's --strict check
# (`cyber_strict && warnings > 0`) never consults dispositions at all, so
# no waiver entry changes its outcome. Turning --strict on today would
# therefore require either fixing several hundred call sites sight-unseen
# or sprinkling `// fusa:suppress CYBERxxx` at each one purely to satisfy
# the flag — the "soften a gate to make CI pass" move this batch is
# explicitly not supposed to make. So the job keeps running plain `cyber`
# (a real gate on ERROR-severity findings, of which cpp-RCP has none) and
# is named to match.
cpfusa-cyber:
name: cpfusa cyber --strict
name: cpfusa cyber
runs-on: ubuntu-22.04
needs: [build-and-test, cpfusa-build]
steps:
Expand Down
59 changes: 59 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,16 @@ jobs:
--dal DAL-B \
--output do178-gap-report.json || true

# .fusa-iec62443.json (target_sl/component_type/incident_resp_doc) is
# the hand-authored input `cpfusa iec62443` reads; already a required
# artifact per ci.yml's cpfusa-check job. Same non-gating rationale as
# the ISO 26262/IEC 61508/DO-178C gap reports above.
- name: Regenerate IEC 62443 gap report (SL-2, artifact only — non-gating)
run: |
/tmp/cpfusa/build/cpfusa iec62443 \
--sl SL-2 \
--output iec62443-gap-report.json || true

- name: Regenerate structural coverage report (DO-178C, artifact only — non-gating)
run: |
/tmp/cpfusa/build/cpfusa coverage \
Expand All @@ -148,6 +158,53 @@ jobs:
/tmp/cpfusa/build/cpfusa report --format json --output report.json || true
/tmp/cpfusa/build/cpfusa report --format html --output report.html || true

# Release-gate check (mirrors c-RCP's own "Verify shipped artifacts
# declare the version being released" step), adapted to what cpp-FuSa
# v0.18.0's actual output carries for this project. c-RCP's tool
# stamps its generated sbom.json/provenance.json module field as
# "c-RCP@<version>", so its check reads that field directly. cpp-FuSa
# v0.18.0 does not do the equivalent for cpp-RCP: `cpfusa release`'s
# sbom.json/provenance.json/artifact-manifest.json and `cpfusa
# qualify`'s qualify-report.json all hardcode
# "module": "github.com/SoundMatt/cpp-FuSa" regardless of target
# project (verified directly against a local build of the pinned
# v0.18.0 binary) — a real limitation of that pinned tool release, not
# something this repo's own files can fix. report.html is the one
# artifact `cpfusa report` actually generates that renders the target
# project's own name+version ("<b>Project:</b> cpp-RCP v<version>"),
# sourced from .fusa.json's project.version — so it is what this check
# verifies instead, alongside re-confirming .fusa.json itself agrees
# with version.hpp. This re-checks what ci.yml's version-sources-agree
# job already checks on every push, because that job's trigger
# (push to main/rewrite branches) does not fire on a tag push, so nothing
# else guarantees the three sources still agreed at the exact ref this
# release job checked out.
- name: Verify shipped artifacts declare the version being released
run: |
header_version=$(grep -m1 -oE 'kVersion[[:space:]]*=[[:space:]]*"[0-9]+\.[0-9]+\.[0-9]+"' include/rcp/version.hpp | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
if [ -z "$header_version" ]; then
echo "::error file=include/rcp/version.hpp::Could not parse kVersion"
exit 1
fi

fail=0

fusa_version=$(grep -m1 -oE '"version": *"[0-9]+\.[0-9]+\.[0-9]+"' .fusa.json | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
if [ "$fusa_version" != "$header_version" ]; then
echo "::error file=.fusa.json::.fusa.json's project.version is '$fusa_version', but include/rcp/version.hpp says '$header_version' -- every artifact cpfusa generates from .fusa.json (report.html included) is stamped from the stale value."
fail=1
fi

if [ ! -f report.html ]; then
echo "::error::Expected report.html to have been generated by the previous step"
fail=1
elif ! grep -qE "cpp-RCP v${header_version}[[:space:]&<]" report.html; then
echo "::error file=report.html::Does not declare 'cpp-RCP v${header_version}' -- expected this release's compliance report to carry the version being released."
fail=1
fi

[ "$fail" -eq 0 ] || exit 1

- name: Tool qualification evidence
run: /tmp/cpfusa/build/cpfusa qualify

Expand Down Expand Up @@ -179,6 +236,7 @@ jobs:
iso26262-gap-report.json \
iec61508-gap-report.json \
do178-gap-report.json \
iec62443-gap-report.json \
coverage-report.json \
sas.json sas.md \
sci.json \
Expand Down Expand Up @@ -242,6 +300,7 @@ jobs:
iso26262-gap-report.json
iec61508-gap-report.json
do178-gap-report.json
iec62443-gap-report.json
coverage-report.json
audit-pack.zip
fusa-badge.svg
Expand Down
113 changes: 113 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Changelog

All notable changes to cpp-RCP are documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/).

This changelog starts from the ground-up rewrite tracked on
`rewrite/v3-from-c-rcp` (cpp-RCP issue #129, ROADMAP.md Phase 17) and does not
attempt to reconstruct the project's full pre-rewrite history — see git log
for that. Entries below are one line per merged PR/batch, in the order
merged.

## [Unreleased] — v3.0.0 rewrite (`rewrite/v3-from-c-rcp`)

### Phase 7 — release hardening, formal verification, coverage

- Release-pipeline hardening: `version-sources-agree` CI job, real `cpfusa
analyze`/`cpfusa cyber` gating, `.fusa-dispositions.json`, IEC 62443 release
gap report, shipped-artifact version verification (batch 3)
- rewrite(phase7): batch 2 — add real MC/DC coverage ratchet gate (LLVM) (#168)
- rewrite(phase7): batch 1 — port LifecycleStateMachine/E2ESafePoint TLA+
specs, add TLC CI job (#167)

### Phase 6 — requirement catalog re-derivation (complete)

- rewrite(phase6): batch 13 — MOCK/PWRMODE catalog re-derivation (Phase 6
complete) (#166)
- rewrite(phase6): batch 12 — DISC/RELAY catalog re-derivation (#165)
- rewrite(phase6): batch 11 — REQ-REGMAP-\*→REQ-RMAP-\* rename + RMAP/SRV
catalog (#164)
- rewrite(phase6): batch 10 — SPI/UART/WAKEUP catalog re-derivation (#163)
- rewrite(phase6): batch 9 — MDIO/PWM catalog re-derivation (#162)
- rewrite(phase6): batch 8 — I2C/ADC/GPIO catalog re-derivation (#161)
- rewrite(phase6): batch 7 — CANEP/LINEP/ISELED catalog re-derivation (#160)
- rewrite(phase6): batch 6 — E2E/LIFECYCLE catalog re-derivation (#159)
- rewrite(phase6): batch 5 — watchdog: one traceability gap found, no catalog
change (#158)
- rewrite(phase6): batch 3 — conditional-request cluster catalog
re-derivation (#157)
- rewrite(phase6): batch 2 — FRAG/RESPQUEUE-slice/LOAN catalog re-derivation
(#156)
- rewrite(phase6): batch 1 — ACF/AVTP/WIREERR catalog re-derivation (#155)

### Phase 5 — admin/shmem and transport dispatch wiring

- rewrite(phase5): admin.hpp — fixed-capacity subscriber/counter bounds, port
deadlock fix (#154)
- rewrite(phase5): shmem.hpp — rebuild Channel around a real bounded
byte-level buffer (#153)
- rewrite(phase5): l2.hpp — add FrameHandler wired to Phase 4 frame-level
dispatch (#152)
- rewrite(phase5): udp.hpp — wire Server::Handler to Phase 4 frame-level
dispatch (#151)

### Phase 4 — mock dispatch, discovery, register map, server admission

- rewrite(phase4): mock.hpp batch D2 — AVTPDU frame-level dispatch, closes
out Phase 4 (#150)
- rewrite(phase4): mock.hpp batch D1 — wire fragment.hpp/respqueue.hpp for
E2E fragmented dispatch (#149)
- rewrite(phase4): mock.hpp batch C — wire RxSequenceGuard,
StreamFaultTracker, RxWatchdog (#148)
- rewrite(phase4): mock.hpp batch B — Table 24 response suppression +
regmap/discovery wiring (#147)
- rewrite(phase4): mock.hpp batch A — wire server::Endpoint admission (#146)
- rewrite(phase4): fix adapt.hpp's missing read_size_or_segment_num field,
add test_adapt.cpp (#145)
- rewrite(phase4): port discovery from c-RCP, fix claim-release and
validation gaps (#144)
- rewrite(phase4): port regmap batch B from c-RCP — HW pins, streams, EP-ID
map, optional subsystems (#143)
- rewrite(phase4): port server.c admission/scheduling into new server.hpp
(#141)
- rewrite(phase4): port regmap batch A from c-RCP — general map, EP0,
generic/functional split (#142)

### Phase 3 — remaining endpoint types

- rewrite(phase3): port spi and uart from c-RCP, RC5 nr_cs/deassert_cs_pause
fix (#139)
- rewrite(phase3): port pwm and wakeup from c-RCP, fix PWM_OUT Subtract
operand order (#140)
- rewrite(phase3): port mdio from c-RCP, revert an earlier session's own
regression (#138)
- rewrite(phase3): port adc/gpio from c-RCP, fix a critical ADC averaging
regression (#137)
- rewrite(phase3): port can/lin from c-RCP, wire CAN XL fragmentation via
fragment.hpp (#136)
- rewrite(phase3): port iseled/i2c from c-RCP; fix ROADMAP.md's Phase 17
missing i2c entry (#135)

### Phase 2 — E2E/lifecycle/watchdog

- rewrite(phase2): port e2e/lifecycle from c-RCP, correct HARA.md's
overstated H-004 claim (#134)
- rewrite(phase2): port watchdog + build allocation fault-injection seam,
ported from c-RCP (#133)

### Phase 1 — core wire format foundation

- rewrite(phase1): port request/sequencer/scheduler from c-RCP's
RC5-conformant reference (#132)
- rewrite(phase1): add fragment/respqueue, convert loan to fixed-capacity,
ported from c-RCP (#131)
- rewrite(phase1): port acf.hpp/avtp.hpp from c-RCP's RC5-conformant
reference (#130)

### Rewrite kickoff

- ci: run CI/DCO on the rewrite/v3-from-c-rcp branch too
- docs(roadmap): v3.0.0 becomes a full rewrite ported from c-RCP, not Phase
16's organic conclusion
Loading