Cybersecurity-Projects/PROJECTS/intermediate/docker-security-audit/internal/report/reporter.go

79 lines
1.7 KiB
Go

/*
©AngelaMos | 2026
reporter.go
Reporter interface and factory that dispatches to format-specific
implementations
NewReporter selects and constructs a TerminalReporter, JSONReporter,
SARIFReporter, or JUnitReporter based on the format string. When
outputFile is empty, output goes to stdout. baseReporter holds the
shared writer and closer for the concrete implementations.
Key exports:
Reporter - interface with Report(findings Collection) error
NewReporter - factory returning the correct implementation
Connects to:
scanner.go - calls NewReporter with cfg.Output and cfg.OutputFile
terminal.go, json.go, sarif.go, junit.go - implement Reporter
finding.go - Report() accepts finding.Collection
*/
package report
import (
"fmt"
"io"
"os"
"github.com/CarterPerez-dev/docksec/internal/finding"
)
type Reporter interface {
Report(findings finding.Collection) error
}
func NewReporter(format, outputFile string) (Reporter, error) {
var w io.Writer = os.Stdout
var closer func() error
if outputFile != "" {
f, err := os.Create(outputFile)
if err != nil {
return nil, fmt.Errorf("creating output file: %w", err)
}
w = f
closer = f.Close
}
switch format {
case "terminal", "":
return &TerminalReporter{
w: w,
closer: closer,
colored: outputFile == "",
}, nil
case "json":
return &JSONReporter{w: w, closer: closer}, nil
case "sarif":
return &SARIFReporter{w: w, closer: closer}, nil
case "junit":
return &JUnitReporter{w: w, closer: closer}, nil
default:
return nil, fmt.Errorf("unsupported output format: %s", format)
}
}
type baseReporter struct {
w io.Writer
closer func() error
}
func (r *baseReporter) close() error {
if r.closer != nil {
return r.closer()
}
return nil
}