Skip to content

feat: centralize report filename construction - #789

Open
trevor-vaughan wants to merge 1 commit into
mainfrom
opsx/773-output-overwritten
Open

feat: centralize report filename construction#789
trevor-vaughan wants to merge 1 commit into
mainfrom
opsx/773-output-overwritten

Conversation

@trevor-vaughan

Copy link
Copy Markdown
Member

Summary

Multi-target scans under the same policy produced OSCAL, SARIF, and Markdown reports with identical filenames (only policyID + timestamp), causing overwrites when targets processed within the same second. The EvaluationLog formatter already included targetID and was unaffected.

This PR adds a BuildReportFilename helper in internal/output/filename.go that all four formatters now call. Report filenames include the target ID, matching the EvaluationLog pattern.

Related Issues

Changes

  • New helper: BuildReportFilename(prefix, policyID, targetID, ext) in internal/output/filename.go
    • Sanitizes IDs via FilenameSafe, timestamps via time.Now().Format("20060102-150405")
    • Omits targetID segment when empty (no double dashes)
  • Formatters migrated: OSCAL, SARIF, Markdown, and EvaluationLog now call the shared helper
    • Removes inline fmt.Sprintf from each formatter
  • Tests updated:
  • Docs: CHANGELOG.md and AGENTS.md entries added

Review Hints

  • The filename helper is in internal/output/filename.go with comprehensive tests in filename_test.go
  • Each formatter (evaluator.go, oscal.go, sarif.go, markdown.go) has a one-line change replacing fmt.Sprintf with BuildReportFilename
  • The regression test TestMultiTargetDistinctFilenames in oscal_test.go reproduces the original bug (scanning two targets produces two distinct files)
  • All OpenSpec artifacts are in openspec/changes/multi-target-report-filenames/ (proposal, design, spec, tasks)

Testing

  • Unit tests pass (make test-unit)
  • Lint passes (make lint)
  • Vet passes (make vet)
  • CRAP load check passes (make crapload-check)
  • Regression test added (TestMultiTargetDistinctFilenames)

@trevor-vaughan trevor-vaughan added bug Something isn't working enhancement New feature or request llm_assisted Filed or drafted with LLM assistance labels Jul 29, 2026
@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

✅ CRAP Load Analysis: PASS

Summary

Metric Value
Functions analysed 43
Avg complexity 3.8
Avg line coverage 93.9%
Avg CRAP score 3.9
CRAPload (>= 15) 0
Avg contract coverage 85.7%
Avg GazeCRAP score 3.7
GazeCRAPload (>= 15) 0
Regressions 0
Improvements 0
New functions 1

Quadrant Distribution

Quadrant Count
Q1 Safe 7
Q2 Complex but Tested 0
Q3 Simple but Underspecified 0
Q4 Dangerous 0

New Functions

Status Function CRAP GazeCRAP Note
+ internal/output/filename.go:BuildReportFilename 2 2 new

View full analysis logs

@trevor-vaughan trevor-vaughan changed the title Centralize report filename construction feat: centralize report filename construction Jul 29, 2026
@trevor-vaughan
trevor-vaughan marked this pull request as ready for review July 29, 2026 21:12
@trevor-vaughan
trevor-vaughan requested a review from a team as a code owner July 29, 2026 21:12

@SecKatie SecKatie left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like a good fix!

em-redhat
em-redhat previously approved these changes Jul 30, 2026

@em-redhat em-redhat left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean, well-tested fix for multi-target report overwrites (#773). BuildReportFilename is a solid centralization, import cleanup is thorough, and test coverage is strong across all formatters. One non-blocking nit on openspec/config.yaml noted inline.

Comment thread openspec/config.yaml
@trevor-vaughan
trevor-vaughan force-pushed the opsx/773-output-overwritten branch 2 times, most recently from 4abd374 to bb97b04 Compare August 3, 2026 15:58
hbraswelrh
hbraswelrh previously approved these changes Aug 3, 2026

@hbraswelrh hbraswelrh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Nice change.

OSCAL/SARIF/Markdown formatters add targetID to filenames via
BuildReportFilename helper, matching EvaluationLog; fixes
multi-target scan overwrite.

- feat(output): add BuildReportFilename for consistent naming
  - Sanitize policyID/targetID via FilenameSafe, timestamp via time.Now()
  - Omit targetID when empty (no double dashes)
- refactor(output): migrate formatters to shared helper
  - Remove inline fmt.Sprintf from evaluator/oscal/sarif/markdown
- test(output): add targetID assertions to formatter tests
  - mockGemaraEvalLog adds Target field, tests verify targetID in output
- test(output): add regression test for multi-target collision
  - TestMultiTargetDistinctFilenames verifies distinct filenames per target
- docs: update CHANGELOG and AGENTS.md for #773

Closes: #773

Assisted-By: Claude Opus 4.6
Signed-off-by: Trevor Vaughan <tvaughan@redhat.com>
@trevor-vaughan
trevor-vaughan dismissed stale reviews from hbraswelrh and em-redhat via b0abfe0 August 4, 2026 15:00
@trevor-vaughan
trevor-vaughan force-pushed the opsx/773-output-overwritten branch from bb97b04 to b0abfe0 Compare August 4, 2026 15:00
@trevor-vaughan
trevor-vaughan enabled auto-merge (rebase) August 4, 2026 15:01

@hbraswelrh hbraswelrh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request llm_assisted Filed or drafted with LLM assistance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OSCAL/SARIF scan output overwritten per-target — only last target's results survive

4 participants