Multi-language functional safety orchestration.
FuSaOps sits on top of the x-FuSa toolchain — go-FuSa, c-FuSa, cpp-FuSa, rust-FuSa, py-FuSa, java-FuSa, ada-FuSa and future language tools — and gives mixed-language repositories a single, intuitive way to scan, aggregate, and report functional safety evidence. One command runs the right tool for every language present and merges their results into one report and one web dashboard.
FuSaOps does not reimplement language-specific safety rules. It detects the languages in a repo, delegates to each language's x-FuSa tool, normalises the machine-readable output, and presents a unified PASS/WARN/FAIL view for ISO 26262, IEC 61508, ISO 21434, DO-178C and related safety cases.
It is NOT a certification product. It is an engineering accelerator that reduces the cost of producing functional safety evidence across a polyglot codebase.
New to FuSaOps?
docs/getting-started.mdis a step-by-step guide to applying it to a real project — zero-config first scan, config file, CI gate, regression-only gating, dashboard, and deeper safety evidence. Everything below this point is the full reference; start there if you just want to get it running.
┌────────────────────────────────── FuSaOps ──────────────────────────────────┐
repo ──▶ │ scan (detect languages) ──▶ orchestrator ──▶ aggregate report │ ──▶ text / json / html / sarif
│ │ │ ──▶ web dashboard (fusaops serve)
└───────────────────────────────────┼────────────────────────────────────────┘
│
┌──────────────┬──────────────┬────────┴─────────┬──────────────┐
▼ ▼ ▼ ▼ ▼
gofusa (Go) cfusa (C) cpfusa (C++) rsfusa (Rust) pyfusa (Python)
check --format json … … … …
Each adapter runs <tool> check --format json, FuSaOps decodes the common
report schema, tags every finding with its language and tool, and merges them.
Adapters whose language is present but whose binary is not installed are
recorded as skipped components — coverage gaps are never silently dropped.
go install github.com/SoundMatt/FuSaOps/cmd/fusaops@latestThe adapter tools must be on PATH for the languages you want scanned
(gofusa, cfusa, cpfusa, rsfusa, pyfusa, jfusa, adafusa). The Docker image bundles all seven.
fusaops scan # detect languages and applicable adapters
fusaops adapters # list adapters and whether each tool is installed
fusaops check # run every applicable tool; exit 1 on ERROR findings
fusaops check --strict # also exit 1 on WARNING findings
fusaops check --min-severity ERROR # show only ERROR findings (suppress INFO and WARNING)
fusaops report --format html --output fusaops-report.html
fusaops diff --baseline check-report.json # compare baseline; exit 1 on new errors
fusaops diff --strict # exit 1 on any new finding (not just errors)
fusaops trace # cross-language requirement traceability + qualification
fusaops trace --strict # CI gate: fail on any untraced/untested requirement
fusaops sbom --format spdx # merged cross-language SBOM (SPDX 2.3)
fusaops audit-pack # bundle every language's evidence into audit-pack.zip
fusaops iso26262 # roll up ISO 26262 gap reports across all languages
fusaops iec61508 # roll up IEC 61508 gap reports across all languages
fusaops do178 # roll up DO-178C gap reports across all languages
fusaops iso21434 # roll up ISO 21434 gap reports across all languages
fusaops unece # roll up UNECE R155/R156 gap reports across all languages
fusaops iec62443 # roll up IEC 62443 gap reports across all languages
fusaops trace --gaps # show only untraced/untested requirements
fusaops trace --format markdown --output TRACE.md # GFM traceability matrix for wikis/PRs
fusaops trace --req-coverage 80 --sec-tested 60 # threshold-based coverage gate
fusaops conform gofusa # check a binary against the x-FuSa spec
fusaops serve --addr :8080 # launch the web dashboard
fusaops serve --auth user:pass # enable HTTP Basic Auth
fusaops serve --tls-cert c.pem --tls-key k.pem # HTTPS
fusaops serve --fleet fleet.json # add /fleet multi-repo dashboard
fusaops init # write a starter .fusaops.json
fusaops config validate # validate .fusaops.json; exit 1 on error
fusaops config show # print effective config as formatted JSON
fusaops history list # list check-run history (text or json)
fusaops history prune --keep 50 # trim history to 50 most-recent entriesBeyond the core scan/check/report loop, FuSaOps has a full set of DO-178C,
ISO 26262, and ISO 21434 evidence-generation and project-workflow commands.
See docs/commands/ for full flag references.
fusaops comp --dal DAL-B # cross-language McCabe cyclomatic complexity (V(G))
fusaops coverage --dal DAL-C coverage.out # DO-178C structural coverage from a Go profile
fusaops coverage --mcdc --mcdc-file mcdc.json --dal DAL-A # LLVM source-based MC/DC gate
fusaops req # show requirements from .fusa-reqs.json
fusaops req import --file reqs.csv # import requirements (csv/doors/polarion/codebeamer/jama)
fusaops req export --format doors # export requirements to an external RM tool format
fusaops policy --policy policy.json # evaluate org-wide safety rules over the scan
fusaops fleet --config fleet.json # run check across every repo in a fleet
fusaops metrics record # snapshot project safety metrics over time
fusaops metrics show --format json # show the recorded metrics time series
fusaops badge --output badge.svg check-report.json # SVG status badge for a README
fusaops slsa --level L3 # SLSA v1.0 supply-chain integrity gap report
fusaops capabilities # report supported commands/formats/standards as JSON
fusaops hooks install # install a pre-commit hook running check --strict
fusaops impact --from main --to HEAD # requirements/evidence impacted by a code change
fusaops disposition add --rule SAFETY017 --reviewer "J. Rivera" --rationale "false positive"
fusaops pr add --id PR-001 --title "Race in aggregation" --severity major # DO-178C §11.17 problem reports
fusaops verify # run go test and save a test evidence bundle
fusaops sign --key release.key audit-pack.zip # HMAC-SHA256 sign a release artefact
fusaops qualify # tool qualification report for installed adapters
fusaops release --output-dir dist/ # cross-language SBOM + provenance + artifact manifest
fusaops safety-case --standard "DO-178C" # assemble a structured safety argument from evidence
fusaops sci # Software Configuration Index (DO-178C §11.16)
fusaops sas --level DAL-B # Software Accomplishment Summary (DO-178C §11.20)
fusaops tara # Threat Analysis and Risk Assessment (ISO 21434 Clause 15)
fusaops fmea # Design FMEA of the orchestration pipeline
fusaops vuln # scan dependency manifests for known vulnerabilities
fusaops template --standards "ISO 26262" # generate safety documentation templates
fusaops hara init # create a starter Hazard Analysis / Risk Assessment
fusaops hara asil -s S2 -e E3 -c C2 # derive ASIL from S/E/C (ISO 26262-3 Table 4)
fusaops vv show # V&V independence declarations + achievable ASILBeyond aggregating findings, FuSaOps rolls up the evidence each tool already produces into one cross-language view:
fusaops trace— merges every tool's requirement traceability matrix and qualification status;--strictis a polyglot coverage gate. Supports--format text|json|html|markdown; themarkdownformat emits a GitHub-Flavoured Markdown summary suitable for wikis and PR descriptions.fusaops sbom— merges and de-duplicates every tool's SBOM. Supports--format json|text|spdx|html; thehtmlformat produces a self-contained HTML viewer with a per-component summary and a full de-duplicated package list.fusaops audit-pack— bundles each tool's own audit-pack plus the FuSaOps aggregate report, trace matrix, and SBOM into one ZIP with a hashed manifest.
fusaops iso26262— rolls up ISO 26262 gap reports from each language tool into one cross-language PASS/GAP matrix;--strictexits 1 on any gap.fusaops iec61508— same for IEC 61508.fusaops do178— same for DO-178C (maps to thedo178ccanonical id).fusaops iso21434— same for ISO 21434 (automotive cybersecurity).fusaops unece— same for UNECE R155/R156 (vehicle cybersecurity management).fusaops iec62443— same for IEC 62443 (industrial cybersecurity).
fusaops diff --baseline <file>— compares a stored baselinecheck-report.jsonwith the findings from a fresh scan, matching by fingerprint (§4.2). Exit 0 when no new errors; exit 1 when new errors appear.--strictwidens the gate to any new finding. Ideal CI step after storing a clean-baseline artifact.
In .fusaops.json, pin specific sub-directories to specific adapters and run
everything in parallel:
{
"run": { "timeout": "60s", "workers": 4 },
"scan": {
"components": [
{ "path": "services/auth", "adapter": "gofusa", "timeout": "30s" },
{ "path": "drivers/safety", "adapter": "cfusa" }
]
}
}fusaops conform <binary>— validates any x-FuSa tool binary against the spec v1.15 schema and behavioural invariants. Per spec §16 step 7, this is a MUST gate for onboarding a new language tool. Seedocs/conformance.md.
See docs/commands/ for each command.
fusaops serve
# open http://localhost:8080The dashboard shows an overall status badge, per-language summary cards, and a filterable findings table. The page is fully self-contained (no external assets).
| Endpoint | Description |
|---|---|
/ |
HTML dashboard — PASS/WARN/FAIL badge, per-language cards, findings table |
/history |
HTML trend page — PASS/FAIL badges, severity bars, per-language breakdown |
/refresh |
Re-runs the scan and updates the dashboard |
/api/report |
Full aggregate JSON report |
/api/history |
JSON array of run snapshots (persisted in .fusaops-history.jsonl) |
/api/v1/status |
Lightweight poll endpoint: {"status":"PASS","errors":0,"warnings":1,"total":1} |
/api/v1/findings |
Filtered findings: ?severity=ERROR&language=go&tool=gofusa |
/api/v1/report |
Versioned alias for /api/report |
/api/v1/history |
Versioned alias for /api/history |
/api/v1/export?format=FORMAT |
Download the cached report in any supported format (json, text, html, sarif, junit, csv, markdown). Response carries Content-Disposition: attachment so browsers save it directly. Multi-project mode exports a merged fleet report. |
GET /api/v1/diff?baseline=PATH[&strict=true][&format=json|text][&project=name] |
Compare the cached report against a baseline file. Returns the delta (added/removed findings). strict=true → 409 Conflict when new ERROR findings exist. Multi-project: add ?project=name to diff one project; omit to diff the merged fleet. |
POST /api/v1/baseline |
Save the current cached findings as a baseline file (path set via --baseline). Returns {"saved":"path","findings":N}. |
Run history is persisted to .fusaops-history.jsonl automatically; the /history trend page
and /api/history endpoint are available after the first run.
Scan multiple repositories with one command:
fusaops fleet --config fleet.json # columnar text output
fusaops fleet --config fleet.json --format json
fusaops fleet --config fleet.json --strict # exit 1 on any WARNINGFleet config format:
{
"project": "my-system",
"repos": [
{ "name": "firmware", "dir": "/path/to/firmware", "adapter": "cfusa" },
{ "name": "app", "dir": "/path/to/app" }
]
}Each repo is scanned in parallel. adapter is optional — omitting it detects
languages automatically. The output is a columnar table (or JSON) with per-repo
PASS/WARN/FAIL status and finding counts.
Codify org-wide safety gates in a JSON policy file:
fusaops policy --policy policy.json # evaluate against current scan
fusaops policy --policy policy.json --dir ./src
fusaops policy --policy policy.json --format jsonPolicy config format:
{
"name": "ci-gate",
"rules": [
{ "id": "no-errors", "requireStatus": "WARN" },
{ "id": "go-strict", "language": "go", "requireStatus": "PASS" },
{ "id": "cpp-error-budget", "language": "cpp", "maxErrors": 5 }
]
}Each rule can scope to a language and/or tool, and can enforce maxFindings,
maxErrors, maxWarnings, and/or requireStatus (PASS = zero errors + zero
warnings; WARN = zero errors, warnings allowed). fusaops policy exits 1 if
any rule fails.
fusaops serve can be hardened for team and enterprise use:
# Password-protect the dashboard (HTTP Basic Auth)
fusaops serve --auth admin:secret
# HTTPS (TLS 1.2+)
fusaops serve --tls-cert /etc/certs/server.pem --tls-key /etc/certs/server-key.pem
# Combined fleet + auth + HTTPS
fusaops serve \
--fleet fleet.json \
--auth admin:secret \
--tls-cert server.pem --tls-key server.keyWhen --fleet is set, the server adds two routes to the existing dashboard:
/fleet— HTML page: per-repo PASS/WARN/FAIL badge, error/warning counts/api/fleet— JSON: fullFleetReportfor CI polling
Serve multiple repositories from a single process:
fusaops serve --projects projects.jsonprojects.json format:
{
"projects": [
{ "name": "firmware", "dir": "/path/to/firmware" },
{ "name": "app", "dir": "/path/to/app", "adapter": "gofusa" }
]
}All projects are scanned in parallel on startup and on /refresh. Routes:
/— HTML grid of project status cards (badge, counts, detail link)/api/projects— JSON array of all project statuses/p/{name}— HTML findings table for a single project
All enterprise flags (--auth, --auth-ro, --audit-log, --tls-cert) compose with --projects.
Both Server and MultiServer expose embeddable SVG badges:
| Route | Description |
|---|---|
/badge/status.svg |
Overall PASS/WARN/FAIL/pending badge |
/badge/{name}/status.svg |
Per-project badge (multi-project mode) |
Embed in a README:
Badge colours follow shields.io convention: green (PASS), yellow (WARN), red (FAIL/error), gray (pending). Responses carry Cache-Control: no-cache.
fusaops serve --webhook https://hooks.example.com/fusaopsWhen the aggregate status transitions (e.g. PASS → FAIL), FuSaOps POSTs:
{"status":"FAIL","prev":"PASS","errors":3}The server retries once after 2 seconds on failure. Webhooks integrate with Slack, PagerDuty, or any HTTP receiver.
fusaops serve --refresh-interval 5mRescans automatically in the background every 5 minutes without a manual /refresh. Accepts any Go duration (1h, 30s, etc.). Compose with --webhook to push alerts as the status evolves.
GET /metrics returns an OpenMetrics text exposition compatible with Prometheus, VictoriaMetrics, and any OpenMetrics scraper:
# HELP fusaops_findings_total Total findings by severity
# TYPE fusaops_findings_total gauge
fusaops_findings_total{severity="error"} 3
fusaops_findings_total{severity="warning"} 12
fusaops_findings_total{severity="info"} 0
# HELP fusaops_status Aggregate status: 1=PASS 2=WARN 3=FAIL 0=pending/error
# TYPE fusaops_status gauge
fusaops_status 2
# EOF
In multi-project mode (--projects), all series carry a project label:
fusaops_findings_total{project="firmware",severity="error"} 1
fusaops_status{project="firmware"} 1
Add to your prometheus.yml:
scrape_configs:
- job_name: fusaops
static_configs:
- targets: ["localhost:8080"]Acknowledge known findings with .fusaops-suppress.json:
{
"suppressions": [
{"fingerprint": "abc123", "reason": "false positive, reviewed 2026-06-01"},
{"fingerprint": "def456", "reason": "accepted risk JIRA-42", "expires": "2026-12-31"}
]
}Pass the file to check or report:
fusaops check --suppress-file .fusaops-suppress.json
fusaops report --suppress-file .fusaops-suppress.json --format jsonManage the suppression file from the CLI:
fusaops suppress add --fingerprint sha256:abc123 --reason "false positive" [--expires 2026-12-31]
fusaops suppress import --from check.json --reason "acknowledged" # bulk-import from check report
fusaops suppress list # show all entries with active/expired status
fusaops suppress prune # remove expired entries
fusaops suppress verify [--dir .] # check for stale entries not in current findings; exit 1 if any- Suppressions match on spec §4.2
fingerprintfields. expires(ISO-8601YYYY-MM-DD) deactivates the suppression after that day, so findings resurface automatically.- The aggregate text report appends
(N suppressed)to the TOTAL line. AggregateReport.Suppressedin the JSON output holds the count.AggregateReport.SuppressedComponentslists the tool names of components with suppressions applied.- Each
Component.SuppressedFindingsholds the filtered findings for audit traceability.
Use --show-suppressed on check or report to include suppressed findings in output:
fusaops check --suppress-file .fusaops-suppress.json --show-suppressed
fusaops report --suppress-file .fusaops-suppress.json --show-suppressed --format html > report.html- Text: suppressed findings printed after active findings with
[SUPPRESSED]prefix; omitted by default with a count hint. - HTML: a collapsible
<details>section per component;--show-suppressedexpands it. - Markdown: same
<details>pattern;--show-suppressedadds theopenattribute. - JSON:
suppressedFindingsalways serialised regardless of the flag.
Save the current findings as a baseline in a single step:
fusaops check --save-baseline baseline.json
# later, in CI:
fusaops diff --baseline baseline.json --strict--save-baseline calls diff.SaveBaseline after the scan and prints Saved baseline to baseline.json (N findings).
Use --show-fingerprints to print the fingerprint (and a ready-to-run suppress add command) beside each active finding:
fusaops check --show-fingerprints
fusaops report --show-fingerprints --format markdown > report.md- Text: two lines per finding —
fingerprint: sha256:<hex>and$ fusaops suppress add --fingerprint sha256:<hex> --reason "". - HTML: a monospace chip below the message cell with a tooltip holding the full scaffold command.
- Markdown: a
Fingerprintcolumn added to the GFM findings table. - The orchestrator auto-computes a fingerprint for any finding the tool did not provide.
--format junit on fusaops check or fusaops report produces JUnit XML for CI
systems that natively display test results (Jenkins, Azure DevOps, CircleCI, GitLab,
GitHub Actions test summary action):
fusaops check --format junit > fusaops-results.xml
fusaops report --format junit --output fusaops-results.xml- Each language/tool component maps to a
<testsuite name="go/gofusa">. - Each finding maps to a
<testcase>; ERROR and WARNING findings carry a<failure>. - Components with zero findings emit a synthetic
<testcase name="(no findings)"/>(passed). - Skipped / unavailable tools emit
<testcase name="(skipped)"><skipped/></testcase>.
--format csv on fusaops check or fusaops report produces RFC 4180 CSV for
import into Excel, Google Sheets, or auditing spreadsheets:
fusaops report --format csv --output fusaops-findings.csvColumns: language, tool, ruleId, severity, message, file, line, column, category, fingerprint.
--format markdown (or --format md) on fusaops check or fusaops report produces
GitHub-Flavored Markdown for PR comments, wiki pages, or any GFM-capable destination:
fusaops report --format markdown --output fusaops-report.md
# Paste into a GitHub PR comment:
fusaops check --format markdown >> $GITHUB_STEP_SUMMARYOutput includes a shields.io status badge, a summary table, and per-component finding tables with emoji severity icons. Pipe characters in messages are escaped for GFM compatibility.
The published image is all-in-one: it bundles the x-FuSa tools, so there is
nothing else to install. Mount your repo at /project.
# Scan / check a repo (no local Go, no tool installs)
docker run --rm -v "$(pwd)":/project ghcr.io/soundmatt/fusaops scan
docker run --rm -v "$(pwd)":/project ghcr.io/soundmatt/fusaops check
# Web dashboard
docker run --rm -p 8080:8080 -v "$(pwd)":/project \
ghcr.io/soundmatt/fusaops serve --addr :8080
# or: docker compose up → http://localhost:8080How the image stays current. Each tool binary is copied from that tool's own
published image (ghcr.io/soundmatt/<x>-fusa). When an x-FuSa releases, a
repository_dispatch rebuilds ghcr.io/soundmatt/fusaops:latest with the fresh
tool — no manual rebuild, and FuSaOps itself does not need a new release. A
weekly scheduled rebuild is the safety net. See
docs/extending.md.
Bundled tools. The all-in-one image bundles all seven x-FuSa tools: go-FuSa v0.33.4, cpp-FuSa v0.14.3, c-FuSa v0.5.42, rust-FuSa v0.3.8, py-FuSa v0.2.6, java-FuSa v0.4.5, ada-FuSa v0.1.0 (alpha). All are published to GHCR — see each tool's own release notes for its current spec version.
The image is
linux/amd64(the tool images are amd64). On Apple Silicon it runs under emulation; add--platform linux/amd64if your client needs it.
.fusaops.json is optional — FuSaOps works zero-config by detecting languages
directly. When present it sets the project name, restricts which adapters run,
and sets report defaults:
{
"version": "1",
"project": { "name": "my-system", "standard": "ISO26262" },
"scan": { "adapters": ["gofusa", "cpfusa"], "exclude": ["third_party"] },
"report": { "format": "html", "output": "fusaops-report.html" }
}Per-language configuration stays in each component's own x-FuSa config (e.g. a
Go module's .fusa.json); FuSaOps does not manage it.
# Validate the config file — exits 0 on success, 1 on error (CI-friendly)
fusaops config validate
# Validate a specific file
fusaops config validate --file /path/to/.fusaops.json
# Print the effective config as formatted JSON
fusaops config showBoth commands accept --dir DIR (default .) or --file PATH to locate the config file.
fusaops config validate is useful as a CI pre-flight step before running fusaops check.
The reusable action wraps the all-in-one Docker image — no Go installation or tool setup needed in your CI:
steps:
- uses: actions/checkout@v4
- uses: SoundMatt/FuSaOps/.github/actions/fusaops@v0.9.0
# Runs "fusaops check" by default; exit 1 on any ERROR finding, any language.
# With options:
- uses: SoundMatt/FuSaOps/.github/actions/fusaops@v0.9.0
with:
args: '--strict' # also gate on WARNING findings
upload-report: 'true' # attach fusaops-report.html as a workflow artifactAction inputs:
| Input | Default | Description |
|---|---|---|
command |
check |
Any fusaops subcommand (check, trace, report, sbom, audit-pack, ...) |
args |
(empty) | Extra flags appended after the command |
image |
ghcr.io/soundmatt/fusaops:latest |
Docker image to pull |
upload-report |
false |
When "true", generates an HTML report and uploads it as fusaops-report artifact |
See .github/fusaops-example.yml for more usage patterns.
- run: go install github.com/SoundMatt/FuSaOps/cmd/fusaops@latest
- run: fusaops check # fails the build on any ERROR finding, any languageFuSaOps is written in Go, so it eats its own dog food: the go-FuSa self-check
CI job installs gofusa and runs gofusa check against the FuSaOps source on
every run, gating on ERROR findings (see .github/workflows/ci.yml). CodeQL and
a SARIF upload of those findings run alongside it. The toolchain FuSaOps
orchestrates also gates FuSaOps itself.
| Language | Adapter | Tool | Bundled in image |
|---|---|---|---|
| Go | go-FuSa | gofusa |
✅ (v0.34.0, spec v1.10) |
| C++ | cpp-FuSa | cpfusa |
✅ (v0.14.4, spec v1.10) |
| C | c-FuSa | cfusa |
✅ (v0.5.45, spec v1.11) |
| Rust | rust-FuSa | rsfusa |
✅ (v0.3.9, spec v1.10) |
| Python | py-FuSa | pyfusa |
✅ (v0.2.7, spec v1.10, alpha) |
| Java | java-FuSa | jfusa |
✅ (v0.4.6, spec v1.10, alpha) |
| Ada/SPARK | ada-FuSa | adafusa |
✅ (v0.1.0, spec v1.11, alpha) |
All seven adapters exist; an un-bundled tool reports as not installed until
its image publishes. New languages are added by implementing the
adapter.Adapter interface — see docs/extending.md.
FuSaOps is itself developed as an ISO 26262 ASIL-C tool and carries the go-FuSa-grade evidence set. It aggregates evidence relevant to ISO 26262, IEC 61508, ISO 21434, and DO-178C across the languages it orchestrates.
- Requirements —
.fusa-reqs.json(449 requirements);gofusa tracereports them all traced and tested. - HARA —
.fusa-hara.json(tool-failure hazards + safety goals). - Tool Safety Manual — docs/tool-safety-manual.md (intended use, assumptions, hazards, mitigations).
- Qualification — docs/qualification.md (TCL2).
- Standards — docs/standards/ · Commands — docs/commands/ · Release — docs/release-process.md · Incident response — INCIDENT-RESPONSE.md.
- Generated evidence (committed) — safety case, TARA, dFMEA, SBOM, provenance, coupling, cyber, vuln, qualification report, test-evidence bundle.