mirror of
https://github.com/ivuorinen/go-test-sarif.git
synced 2026-02-16 07:50:28 +00:00
feat: replace go-sarif with internal SARIF implementation (#113)
* docs: add design for replacing go-sarif with internal implementation Removes external dependency chain (go-sarif → testify → yaml.v3) by implementing a minimal internal SARIF package with support for v2.1.0 and v3.0 output formats. * docs: add implementation plan for replacing go-sarif 11 tasks covering: - testjson parser with all 7 fields - internal SARIF model and version registry - v2.1.0 and v2.2 serializers - converter refactoring - CLI with --sarif-version and --pretty flags - dependency cleanup * feat(testjson): add parser for go test -json output Add TestEvent struct with all 7 fields from go test -json and ParseFile function to parse test output files line by line. * test(testjson): add tests for all fields, malformed JSON, file not found * feat(sarif): add internal SARIF data model * feat(sarif): add version registry (serializers pending) Add version registry infrastructure for SARIF serialization: - Version type and constants (2.1.0, 2.2) - DefaultVersion set to 2.1.0 - Register() function for version-specific serializers - Serialize() function with pretty-print support - SupportedVersions() for listing registered versions Note: TestSupportedVersions will fail until serializers are registered via init() functions in v21.go and v22.go (Tasks 5/6). * feat(sarif): add SARIF v2.1.0 serializer * feat(sarif): add SARIF v2.2 serializer * test(sarif): add pretty print test * refactor(converter): use internal sarif and testjson packages Replace external go-sarif library with internal packages: - Use internal/sarif for SARIF model and serialization - Use internal/testjson for Go test JSON parsing - Add ConvertOptions struct with SARIFVersion and Pretty options - Remove external github.com/owenrumney/go-sarif/v2 dependency * feat(cli): add --sarif-version and --pretty flags * fix(lint): resolve golangci-lint errors Fix errcheck violation by properly handling f.Close() error return value and add proper package comments to satisfy revive linter. * refactor: consolidate SARIF serializers and fix code issues - Extract shared SARIF types and serialization logic into serialize.go - Simplify v21.go and v22.go to thin wrappers (107/108 → 12 lines each) - Add testConvertHelper() to reduce test duplication in converter_test.go - Remove redundant nested check in converter.go (outer condition already guarantees non-empty) - Fix LogicalLocations: avoid leading dot when Module is empty, set Kind correctly - Increase scanner buffer in parser.go from 64KB to 4MB for large JSON lines - Extract test constants to reduce string literal duplication * docs: fix SARIF v3.0 references to v2.2 SARIF v3.0 doesn't exist. Update design and implementation docs to correctly reference v2.1.0 and v2.2 throughout. * fix: update SARIF 2.2 schema URL and add markdown language identifiers Update schema URL to point to accessible prerelease location and add language identifiers to fenced code blocks to resolve MD040 violations. * chore: add pre-commit config and fix config file formatting Add pre-commit configuration and fix formatting issues in config files including trailing whitespace, YAML document markers, and JSON formatting. * docs: fix markdown linting issues in implementation plan - Convert bold step markers to proper headings - Fix line length violations in header section - Add markdownlint config to allow duplicate sibling headings - Add ecrc config to exclude plan docs from editorconfig checking * chore: update MegaLinter configuration Configure specific linters and add exclusion patterns for test data and generated files. * docs: fix filename in design doc (writer.go → serialize.go) * refactor(tests): fix SonarCloud code quality issues Extract helper functions to reduce cognitive complexity in TestRun and consolidate duplicate string literals into shared testutil package. * docs: add docstrings to exported variables and struct fields Add documentation comments to reach ~98% docstring coverage: - cmd/main.go: document build-time variables - internal/converter.go: document ConvertOptions fields - internal/sarif/model.go: document Report, Rule, Result, LogicalLocation fields - internal/testjson/parser.go: document TestEvent fields * fix(testjson): change FailedBuild field type from string to bool The go test -json output emits FailedBuild as a boolean, not a string. This was causing JSON unmarshal errors. Updated the struct field type and corresponding test assertions. * chore(ci): mega-linter config tweaks for revive
This commit is contained in:
230
docs/plans/2026-01-20-replace-go-sarif-design.md
Normal file
230
docs/plans/2026-01-20-replace-go-sarif-design.md
Normal file
@@ -0,0 +1,230 @@
|
||||
# Design: Replace go-sarif with Internal SARIF Implementation
|
||||
|
||||
## Context
|
||||
|
||||
The `gopkg.in/yaml.v3` dependency is archived and unmaintained.
|
||||
It enters our dependency graph through:
|
||||
|
||||
```text
|
||||
go-sarif/v2 → testify → gopkg.in/yaml.v3
|
||||
```
|
||||
|
||||
This project uses a minimal subset of go-sarif. Replacing it with an
|
||||
internal implementation eliminates all external dependencies and the
|
||||
yaml.v3 vulnerability.
|
||||
|
||||
## Goals
|
||||
|
||||
- Remove go-sarif dependency entirely
|
||||
- Support SARIF v2.1.0 and v2.2 with extensible version system
|
||||
- Capture all `go test -json` fields for future use
|
||||
- Add logical location info (package/test name) to results
|
||||
- Zero external dependencies after migration
|
||||
|
||||
## Package Structure
|
||||
|
||||
```text
|
||||
internal/
|
||||
├── sarif/
|
||||
│ ├── model.go # Internal SARIF data model
|
||||
│ ├── version.go # Version enum and registry
|
||||
│ ├── serialize.go # Common serialization logic
|
||||
│ ├── v21.go # SARIF 2.1.0 serializer
|
||||
│ └── v22.go # SARIF 2.2 serializer
|
||||
├── testjson/
|
||||
│ └── parser.go # Go test JSON parser (all 7 fields)
|
||||
└── converter.go # Orchestrates parsing → model → SARIF output
|
||||
```
|
||||
|
||||
## Internal Data Model
|
||||
|
||||
Version-agnostic model that captures all relevant data:
|
||||
|
||||
```go
|
||||
// internal/sarif/model.go
|
||||
|
||||
type Report struct {
|
||||
ToolName string
|
||||
ToolInfoURI string
|
||||
Rules []Rule
|
||||
Results []Result
|
||||
}
|
||||
|
||||
type Rule struct {
|
||||
ID string
|
||||
Description string
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
RuleID string
|
||||
Level string // "error", "warning", "note"
|
||||
Message string
|
||||
Location *LogicalLocation
|
||||
}
|
||||
|
||||
type LogicalLocation struct {
|
||||
Module string // Package name
|
||||
Function string // Test name
|
||||
}
|
||||
```
|
||||
|
||||
## Test Event Parser
|
||||
|
||||
Captures all 7 fields from `go test -json`:
|
||||
|
||||
```go
|
||||
// internal/testjson/parser.go
|
||||
|
||||
type TestEvent struct {
|
||||
Time time.Time `json:"Time"`
|
||||
Action string `json:"Action"`
|
||||
Package string `json:"Package"`
|
||||
Test string `json:"Test,omitempty"`
|
||||
Elapsed float64 `json:"Elapsed,omitempty"`
|
||||
Output string `json:"Output,omitempty"`
|
||||
FailedBuild string `json:"FailedBuild,omitempty"`
|
||||
}
|
||||
|
||||
func ParseFile(path string) ([]TestEvent, error)
|
||||
```
|
||||
|
||||
Fails fast on malformed JSON with line numbers in error messages.
|
||||
|
||||
## Version Registry
|
||||
|
||||
Extensible system for adding SARIF versions:
|
||||
|
||||
```go
|
||||
// internal/sarif/version.go
|
||||
|
||||
type Version string
|
||||
|
||||
const (
|
||||
Version210 Version = "2.1.0"
|
||||
Version22 Version = "2.2"
|
||||
)
|
||||
|
||||
const DefaultVersion = Version210
|
||||
|
||||
type Serializer func(*Report) ([]byte, error)
|
||||
|
||||
var serializers = map[Version]Serializer{}
|
||||
|
||||
func Register(v Version, s Serializer)
|
||||
func Serialize(r *Report, v Version, pretty bool) ([]byte, error)
|
||||
func SupportedVersions() []string
|
||||
```
|
||||
|
||||
Adding a new version requires:
|
||||
|
||||
1. Create version file (e.g., `v23.go`) with serializer function
|
||||
2. Add version constant
|
||||
3. Register in `init()`
|
||||
|
||||
## Version-Specific Serializers
|
||||
|
||||
Each version has its own JSON schema structs:
|
||||
|
||||
```go
|
||||
// internal/sarif/v21.go
|
||||
|
||||
type sarifV21 struct {
|
||||
Schema string `json:"$schema"`
|
||||
Version string `json:"version"`
|
||||
Runs []runV21 `json:"runs"`
|
||||
}
|
||||
|
||||
func serializeV21(r *Report) ([]byte, error)
|
||||
```
|
||||
|
||||
SARIF v2.2 follows the same pattern with its schema differences.
|
||||
|
||||
## CLI Interface
|
||||
|
||||
```shell
|
||||
go-test-sarif <input.json> <output.sarif>
|
||||
go-test-sarif --sarif-version 2.2 <input.json> <output.sarif>
|
||||
go-test-sarif --pretty <input.json> <output.sarif>
|
||||
go-test-sarif --version
|
||||
```
|
||||
|
||||
Flags:
|
||||
|
||||
- `--sarif-version`: SARIF output version (default: 2.1.0)
|
||||
- `--pretty`: Pretty-print JSON output with indentation
|
||||
- `--version`, `-v`: Display tool version
|
||||
|
||||
Help text for `--sarif-version` dynamically lists registered versions.
|
||||
|
||||
## Go API
|
||||
|
||||
```go
|
||||
// internal/converter.go
|
||||
|
||||
type ConvertOptions struct {
|
||||
SARIFVersion sarif.Version
|
||||
Pretty bool
|
||||
}
|
||||
|
||||
func ConvertToSARIF(inputFile, outputFile string, opts ConvertOptions) error
|
||||
```
|
||||
|
||||
## Output Format
|
||||
|
||||
- Compact JSON by default (no indentation)
|
||||
- `--pretty` flag enables 2-space indented output
|
||||
|
||||
## Error Handling
|
||||
|
||||
- Fail fast on malformed JSON input
|
||||
- Error messages include line numbers
|
||||
- Return error for unsupported SARIF version
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
```text
|
||||
internal/testjson/parser_test.go
|
||||
- TestParseFile_ValidInput
|
||||
- TestParseFile_AllFields
|
||||
- TestParseFile_MalformedJSON
|
||||
- TestParseFile_FileNotFound
|
||||
|
||||
internal/sarif/version_test.go
|
||||
- TestSupportedVersions
|
||||
- TestSerialize_UnknownVersion
|
||||
- TestSerialize_PrettyOutput
|
||||
|
||||
internal/sarif/v21_test.go
|
||||
- TestSerializeV21_Schema
|
||||
- TestSerializeV21_WithResults
|
||||
- TestSerializeV21_LogicalLocation
|
||||
|
||||
internal/sarif/v22_test.go
|
||||
- TestSerializeV22_Schema
|
||||
- TestSerializeV22_WithResults
|
||||
|
||||
internal/converter_test.go
|
||||
- TestConvertToSARIF_Success (update existing)
|
||||
- TestConvertToSARIF_Options
|
||||
```
|
||||
|
||||
## Migration Steps
|
||||
|
||||
1. Implement `internal/testjson/` package
|
||||
2. Implement `internal/sarif/` package with v2.1.0 and v2.2 serializers
|
||||
3. Update `internal/converter.go` to use new packages
|
||||
4. Update `cmd/main.go` with new CLI flags
|
||||
5. Update existing tests, add new tests
|
||||
6. Remove go-sarif import
|
||||
7. Run `go mod tidy`
|
||||
8. Verify: `go mod graph | grep yaml` returns nothing
|
||||
9. Run full test suite
|
||||
|
||||
## Result
|
||||
|
||||
After migration:
|
||||
|
||||
- Zero external dependencies
|
||||
- No yaml.v3 in dependency graph
|
||||
- Extensible SARIF version support
|
||||
- Richer output with logical location info
|
||||
1718
docs/plans/2026-01-20-replace-go-sarif-implementation.md
Normal file
1718
docs/plans/2026-01-20-replace-go-sarif-implementation.md
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user