Skip to content

fix: v0.46.0 — deep-audit round 2 (standard ids, SARIF, tara/qualify/audit-pack) - #84

Merged
SoundMatt merged 8 commits into
mainfrom
fix/audit-round-2-standard-ids-tara-qualify-auditpack
Jul 29, 2026
Merged

fix: v0.46.0 — deep-audit round 2 (standard ids, SARIF, tara/qualify/audit-pack)#84
SoundMatt merged 8 commits into
mainfrom
fix/audit-round-2-standard-ids-tara-qualify-auditpack

Conversation

@SoundMatt

Copy link
Copy Markdown
Owner

Summary

Fixes every genuine defect filed by the latest deep audit (issues #77#83, all confirmed against the current x-FuSa spec text at docs/x-fusa-spec.md before fixing):

#76 was investigated and found stale — the spec was updated to v1.15.1 (already the version pinned in docs/x-fusa-spec.md) explicitly blessing MAJOR.MINOR.PATCH as the correct schemaVersion/specVersion format, reversing the MAJOR.MINOR-only text the issue was filed against. No code change needed; closing separately with an explanation.

Every fix has a regression test that reproduces the original bug (verified failing on the pre-fix code) and passes after.

Test plan

  • go build ./...
  • go vet ./...
  • golangci-lint run ./... — 0 issues
  • go test ./... -cover — all packages pass, coverage ≥ 80% gate
  • Every commit builds/vets independently (checked out and verified in isolation)
  • gofusa trace --dir . — all new requirement ids traced+tested
  • gofusa check --dir . — 0 errors (unchanged baseline)
  • Manually exercised each fixed command end-to-end against this repo

Closes #77, closes #78, closes #79, closes #80, closes #81, closes #82, closes #83

x-FuSa spec §2.9 MUST: tool.driver.name = the §1.1 tool name ("go-FuSa"),
not the "gofusa" binary name. check --format sarif hardcoded the binary
name instead, so the SARIF tool identity diverged from every other JSON
document's "tool" field (which already correctly emits "go-FuSa"),
violating §2.9's format-invariance rule in spirit.

Adds a regression test asserting tool.driver.name == "go-FuSa" in the
rendered SARIF log.

Closes #81

Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
…#77)

x-FuSa spec §2.4.1 MUST: "standard" is a canonical lowercase id (e.g.
"iso26262"), never a display string. 5 of 6 standards commands (all but
slsa) passed a hand-built display string into gapreport.New instead:

  iso26262 -> "ISO 26262 ASIL-B"   now -> "iso26262"
  do178    -> "DO-178C DAL-B"      now -> "do178c"
  iec61508 -> "IEC 61508 SIL-2"    now -> "iec61508"
  iso21434 -> "ISO 21434 CAL-1"    now -> "iso21434"
  unece    -> "UN R.155"           now -> "unece-r155"
  iec62443 -> "iec62443"           now -> "iec62443-4-2" (missing part suffix)

The ASIL/SIL/DAL/CAL rating has no home in the canonical enum (§2.4.1) and
is dropped from the field entirely — it remains available on each
package's internal Report struct (rep.ASIL/DAL/SIL/CAL), it just never
belonged in the canonical gap-report's "standard" value. iec62443's fix
also adds the spec-mandated multi-part suffix identifying which IEC 62443
part is supported (this package assesses IEC 62443-4-2 per its own
package doc). slsa already emitted the correct "slsa" and is unchanged.

Adds/tightens a JSON-envelope regression test in each affected package
asserting the exact canonical id.

Closes #77

Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
x-FuSa spec §2.4.1 MUST: the JSON envelope's "standard" is a canonical
lowercase id, never a display string. cmd_check.go/cmd_report.go wrote
cfg.Project.Standard verbatim into rep.Standard, leaking go-FuSa's
internal uppercase/no-space Standard enum spelling (e.g. "ISO26262")
into the envelope instead of the canonical "iso26262".

Adds config.Standard.CanonicalID(), the inverse of the existing internal
canonicalStandard mapping, and uses it at both call sites.
StandardGeneric/empty both map to "" so the omitempty envelope field is
dropped rather than emitting a non-canonical value.

Closes #78

Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
tara's --output-dir handling didn't create the target directory, unlike
its sibling §9.2 evidence-artifact commands fmea/safety-case, which both
already call os.MkdirAll. Running "gofusa tara --output-dir <not-yet-
existing dir>" surfaced a raw "open ... no such file or directory" OS
error and exited 3, instead of writing tara.json/tara.md like the other
two commands do into a freshly created directory.

Adds an os.MkdirAll(outDir, 0o750) call matching fmea/safety-case, and
strengthens the existing TestRunTara_WithOutputDir test to stop
pre-creating the output directory (which had been silently masking this
exact bug) and assert both tara.json and tara.md now exist afterward.

Closes #83

Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
§6: "<lang>fusa qualify [--dir <path>] [--format text|json] [--output
<file>]". gofusa qualify's flag set only defined -output plus the
qualification-metadata flags — passing --dir or --format failed with
"flag provided but not defined" (exit 2), including the exact
"--format json" invocation §6's own machine-contract language calls out
as required ("Any command whose JSON FuSaOps consumes MUST support
--format json").

Adds both flags: --format is validated to text/json (both currently
produce the same qualification report — the qualification suite itself
always runs the same built-in synthetic cases regardless of project
content, so there's no format-dependent content to diverge on) and
--dir now resolves a projectRoot used to default --output's location,
mirroring how every other command resolves projectRoot.

Closes #82

Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
…evidence (#79)

x-FuSa spec §8 MUST: the pack MUST include every §1.2 input file and
every §1.3 generated file that exists at the project root. EvidenceFiles
was a fixed list dated before tara/hara/cyber/coupling/comp support
existed, so audit-pack silently dropped tara.json, tara.md,
cyber-report.json, coupling-report.json, comp-report.json,
.fusa-hara.json, .fusa-dispositions.json, .fusa-problems.json,
.fusa-model-trace.json, and the entire open-ended
<standard>-gap-report.json family — with no warning that any of it was
missing from the evidence bundle.

Extends EvidenceFiles with the missing fixed-name §1.2/§1.3 files, and
adds a discoverGapReports glob step for the <standard>-gap-report.json
family (whose standard-id set is open-ended, so a fixed list can't
enumerate it), sorted for deterministic manifest/ZIP ordering.

Closes #79

Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
x-FuSa spec §1.6 rule 4 MUST ("Real referents only"): an entry naming a
file MUST refer to an actual file in the analyzed project, not a test
fixture mistaken for one. tara.Scan built threats[] directly and
unfiltered from cyber.Scan's findings, which legitimately include
_test.go files (security issues in test code are still worth flagging
in check's own CYBER category) — but those same findings, unfiltered,
were also becoming TARA "asset under threat" entries. This directly
contradicted the report's own summary.assetInventoryMethod text, which
already documents (correctly) that assetsInProject counts only
non-test .go files via CountProjectFiles.

tara.Scan now skips any cyber finding whose Location.File ends in
"_test.go" before building a ThreatEntry, reusing the same suffix
exclusion CountProjectFiles already applies to the assetsInProject
denominator (so assetsAnalyzed/coveragePct in summary are now internally
consistent with assetInventoryMethod's stated method too). Entry IDs
stay sequential from TARA-001 across the filtered set, with no gaps left
by excluded entries.

Closes #80

Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
Bumps the release version and regenerates the repo's own committed
tara.json/tara.md with the fixed binary, which is itself a live
demonstration of #80's fix: threats[] drops from 321 entries (318 of
which were _test.go fixtures) down to the 3 real project-asset threats
that were always the correct result.

Closes #77, closes #78, closes #79, closes #80, closes #81, closes #82,
closes #83

Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
@github-advanced-security

Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

if code != 0 {
t.Errorf("runQualify --format json: exit %d, stderr: %s", code, errBuf.String())
}
if _, err := os.Stat(outFile); err != nil {
t.Errorf("runQualify --dir: exit %d, stderr: %s", code, errBuf.String())
}
// --output not given, so the report should land under --dir.
if _, err := os.Stat(filepath.Join(dir, "qualify-report.json")); err != nil {
if code != 0 {
t.Errorf("unexpected exit %d: %s", code, errBuf.String())
}
if _, err := os.Stat(filepath.Join(outDir, "tara.json")); err != nil {
if _, err := os.Stat(filepath.Join(outDir, "tara.json")); err != nil {
t.Errorf("tara.json not created in auto-created output dir: %v", err)
}
if _, err := os.Stat(filepath.Join(outDir, "tara.md")); err != nil {
@SoundMatt
SoundMatt merged commit 4c1ff18 into main Jul 29, 2026
16 checks passed
@SoundMatt
SoundMatt deleted the fix/audit-round-2-standard-ids-tara-qualify-auditpack branch July 29, 2026 04:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment