Skip to content

fix: fmea/tara project-relative paths + coveragePct clamp + wider FMEA templates (v0.40.0) - #68

Closed
SoundMatt wants to merge 2 commits into
mainfrom
fix/fmea-tara-paths-and-coverage-quality
Closed

fix: fmea/tara project-relative paths + coveragePct clamp + wider FMEA templates (v0.40.0)#68
SoundMatt wants to merge 2 commits into
mainfrom
fix/fmea-tara-paths-and-coverage-quality

Conversation

@SoundMatt

Copy link
Copy Markdown
Owner

Summary

Closes #59, closes #60. Addresses x-FuSa spec v1.15.0 items 2 and 3 from #64 (item 1, attestation carry-forward, is in a separate PR).

Test plan

  • go build ./...
  • go vet ./...
  • go test -race -count=1 ./... (88.5% total coverage)
  • golangci-lint run ./... (0 issues)
  • go generate ./... (no diff)
  • Manual binary check against this repo's own tree: fmea.json/tara.json entries now use relative paths (analyze/analyze.go, weak.go, etc.), never absolute
  • gofusa fmea against this repo no longer emits a FUSA-STUB002 warning
  • New tests: relative-path assertions for fmea/cyber/tara (unit + cmd-level with --dir omitted), coveragePct-clamp regression tests with a non-trivial test-source tree, IsExcludedDir unit tests

…wider templates

x-FuSa spec §4 requires every Finding.Location.File (and the equivalent
fmea entries[].file) to be project-relative with forward slashes.
Under the common `--dir`-omitted invocation, fmea.Scan's entries[].file
and CYBER's own Finding.Location.File (which tara.Scan sources
threats[].location/sourceFile directly from) both carried the raw,
absolute walked path — reproduced exactly as described against this
repo's own source tree (go-FuSa#59). fmea.Scan now relativizes every
entry's File against projectRoot; cyber.location now does the same
relativization lint/analyze already applied to their own findings
(REQ-LOC-REL001), which transitively fixes tara.json too since it had
no bug of its own — it only ever inherited an absolute path from the
CYBER finding it was built from.

x-FuSa spec §9.2 (spec v1.15.0) states coveragePct MUST NOT exceed 100.
Both fmea.buildSummary and tara.buildSummary already guaranteed this
mathematically via their componentsInProject/assetsInProject >=
componentsAnalyzed/assetsAnalyzed fallback, but add an explicit
defensive clamp anyway — cheap insurance against a future change to
that fallback silently reintroducing the overflow. New regression tests
use a fixture with a non-trivial test-source tree (many _test.go files)
since a fixture with no such tree can't exercise the exclusion logic
the bug depends on.

Separately, this repo's own committed fmea.json failed its own new
FUSA-STUB002 content-quality gate: deriveAnalysis bucketed every
scanned function into one of only 6 fixed template strings, reducing a
461-function codebase to a ~0.013 distinct-value ratio — exactly the
"hundreds of FMEA rows sharing identical boilerplate text" pattern
§1.6.1 rule B exists to catch (go-FuSa#60). Every template now weaves
in the function's own component (a genuine per-function signal) plus,
for the dominant no-signal-matched bucket, whether the function has a
receiver and how many parameters it takes. Regenerated fmea.json/
fmea.csv: distinct-value ratios are now ~0.28-0.29, well clear of 0.1.

Also (x-FuSa spec §1.6 rule 4, SHOULD, non-binding): extracted the
vendor/testdata/dot-directory exclusion check duplicated across
trace.ScanTags/ScanFuncCoverage/ScanFuncTagCoverage,
fmea.CountProjectFunctions, and tara.CountProjectFiles into one shared
trace.IsExcludedDir, so the coverage-denominator scanners this issue
was actually about stop maintaining an independently-drifting copy.

Regenerated tara.json/tara.md for the path fix; tara's own pre-existing
FUSA-STUB002 gap (threats[].threat vocabulary, unrelated to this PR) is
addressed separately.

Signed-off-by: Matt Jones <matt@jellybaby.com>
Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
func TestRunFmea_DirOmitted_EntryFileIsRelative(t *testing.T) {
dir := t.TempDir()
src := "package main\n\n//fusa:req REQ-001\nfunc SafetyFunc() error { return nil }\n"
if err := os.WriteFile(filepath.Join(dir, "main.go"), []byte(src), 0o644); err != nil {
func TestRunTara_DirOmitted_ThreatLocationIsRelative(t *testing.T) {
dir := t.TempDir()
src := "package main\n\nimport \"crypto/md5\"\n\nfunc Hash(b []byte) [16]byte { return md5.Sum(b) }\n"
if err := os.WriteFile(filepath.Join(dir, "weak.go"), []byte(src), 0o644); err != nil {
Comment thread fmea/fmea.go
//
//fusa:req REQ-FMEA002
func deriveAnalysis(name string, returnsErr, hasGoroutine, hasSafetyReq bool) (modes, effects, causes, mitigations []string, sev Severity) {
func deriveAnalysis(name, component string, returnsErr, hasGoroutine, hasSafetyReq, hasReceiver bool, paramCount int) (modes, effects, causes, mitigations []string, sev Severity) {
…nd-coverage-quality

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

# Conflicts:
#	CHANGELOG.md
#	README.md
#	docs/tool-safety-manual.md
#	fusa.go
@SoundMatt
SoundMatt force-pushed the fix/fmea-tara-paths-and-coverage-quality branch from 305bdc4 to 61c3faa Compare July 28, 2026 22:19
@SoundMatt

Copy link
Copy Markdown
Owner Author

Closing and replacing for the same reason as #66/#67: the rebase-onto-main merge commit lacked DCO sign-off, and my fix (amend + force-push) violated the no-force-push rule. Replacing with a fresh branch via cherry-pick.

@SoundMatt SoundMatt closed this Jul 28, 2026
@SoundMatt
SoundMatt deleted the fix/fmea-tara-paths-and-coverage-quality branch July 28, 2026 22:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants