Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
8da347b
build(deps): bump github.com/moby/buildkit from 0.18.0 to 0.18.1 (#1024)
dependabot[bot] Dec 16, 2024
1e7d052
build(deps): bump golang from 1.23.3-alpine to 1.23.4-alpine (#1025)
dependabot[bot] Dec 16, 2024
4299ce7
build(deps): bump alpine from 3.20.3 to 3.21.0 (#1026)
dependabot[bot] Dec 16, 2024
642e7cd
build(deps): bump github.com/magiconair/properties from 1.8.7 to 1.8.…
dependabot[bot] Jan 6, 2025
5b3e926
build(deps): bump github.com/CycloneDX/cyclonedx-go from 0.9.1 to 0.9…
dependabot[bot] Jan 6, 2025
7428841
fix: set jsonnet VM stack limits and add test coverage
thevilledev Jan 15, 2025
8e541da
fix: improve handling for YAML version directives
thevilledev Jan 18, 2025
151643b
fix: add output and tests for GitHub and Azure DevOps
thevilledev Jan 18, 2025
8b34fcb
fix: remove redundant error check in push command
thevilledev Jan 18, 2025
c4e656f
build(deps): bump golang from 1.23.4-alpine to 1.23.5-alpine
dependabot[bot] Jan 20, 2025
163bdd8
fix: prevent policy file overwrite on downloads (#1039)
thevilledev Jan 22, 2025
0bbb473
fix: max stack size already set by jsonnet.MakeVM()
thevilledev Jan 23, 2025
4df824c
build(deps): bump cuelang.org/go from 0.11.0 to 0.12.0
dependabot[bot] Jan 30, 2025
ea55b61
Merge pull request #1051 from open-policy-agent/dependabot/go_modules…
anderseknert Jan 31, 2025
1a4a428
build(deps): bump github.com/moby/buildkit from 0.18.1 to 0.19.0
dependabot[bot] Jan 31, 2025
744f867
Merge pull request #1046 from open-policy-agent/dependabot/go_modules…
anderseknert Jan 31, 2025
1a25844
Merge pull request #1043 from open-policy-agent/dependabot/docker/gol…
anderseknert Jan 31, 2025
154c1aa
build(deps): bump alpine from 3.21.0 to 3.21.2
dependabot[bot] Jan 31, 2025
1d47ac3
build(deps): bump github.com/hashicorp/go-getter from 1.7.6 to 1.7.8
dependabot[bot] Jan 31, 2025
d5e8a77
Merge pull request #1036 from open-policy-agent/dependabot/go_modules…
anderseknert Jan 31, 2025
24e9ca8
chore: optimize yaml document separator handling
thevilledev Jan 31, 2025
3096ca7
Merge pull request #1038 from thevilledev/fix/yaml-preamble-multidoc
anderseknert Jan 31, 2025
6b31946
Merge pull request #1040 from thevilledev/fix/missing-outputs
anderseknert Jan 31, 2025
a603656
Merge pull request #1037 from thevilledev/fix/recursive-jsonnet
anderseknert Jan 31, 2025
aa9e3c8
feat: enable relative jsonnet imports by setting a path-aware importer
thevilledev Jan 20, 2025
326a1a4
Merge pull request #1044 from thevilledev/fix/jsonnet-library-imports
anderseknert Jan 31, 2025
5063084
Merge pull request #1041 from thevilledev/fix/impossible-nil
anderseknert Jan 31, 2025
a770d29
fix: correct linters-settings in .golangci.yaml to enable misspell
thevilledev Jan 31, 2025
356ede4
Merge pull request #1035 from open-policy-agent/dependabot/docker/alp…
anderseknert Jan 31, 2025
6c867fc
Merge pull request #1052 from thevilledev/fix/linters-settings
anderseknert Jan 31, 2025
874f0bc
chore: add nilness check to govet linter
thevilledev Jan 31, 2025
f110dde
Merge pull request #1053 from thevilledev/style/enable-nilness-lint
anderseknert Feb 1, 2025
bad47e2
test(registry): add test for credentials store init failure
thevilledev Feb 1, 2025
3f67b78
feature: Documentation command (#1009)
xNok Feb 5, 2025
26b6c24
Merge pull request #1054 from thevilledev/test/registry-store-init
anderseknert Feb 5, 2025
256bf5e
test(policy): improve engine test coverage (#1055)
thevilledev Feb 8, 2025
19c82bc
build(deps): bump github.com/open-policy-agent/opa from 0.70.0 to 1.1…
dependabot[bot] Feb 9, 2025
6da5673
build(deps): bump golang from 1.23.5-alpine to 1.23.6-alpine (#1062)
dependabot[bot] Feb 11, 2025
eacba23
feat(engine): add query metadata to evaluation results (#1061)
thevilledev Feb 11, 2025
8a44613
engine: Refactor to allow for Rego version to be specified (#1059)
jalseth Feb 15, 2025
5decd18
feat(parser): handle UTF-8 BOM in JSON input (#1065)
thevilledev Feb 15, 2025
9efcd87
test(plugin): add comprehensive plugin package tests (#1056)
thevilledev Feb 15, 2025
abad255
feat: Implement SARIF output (#1042)
thevilledev Feb 15, 2025
155cd3c
chore: Change empty interface{} to any throughout the codebase (#1057)
jalseth Feb 19, 2025
278f735
chore: Update all examples to OPA V1 syntax (#1058)
jalseth Feb 19, 2025
cdd65ba
refactor(output): Add CheckResults type and helpers (#1063)
jalseth Feb 25, 2025
4154949
feat(test): Enable inter-query cache (#1073)
jalseth Feb 25, 2025
6424545
build(deps): bump github.com/open-policy-agent/opa from 1.1.0 to 1.2.…
dependabot[bot] Mar 1, 2025
8e0fdf2
build(deps): bump alpine from 3.21.2 to 3.21.3 (#1072)
dependabot[bot] Mar 1, 2025
6cb9d19
build(deps): bump github.com/moby/buildkit from 0.19.0 to 0.20.0 (#1076)
dependabot[bot] Mar 1, 2025
854183b
refactor(ci): replace Makefile-based Docker builds with GitHub Action…
Amamgbu Mar 1, 2025
43264f4
build(deps): bump golang from 1.23.6-alpine to 1.24.0-alpine (#1071)
dependabot[bot] Mar 1, 2025
d62aa8d
feat: add --absolute-paths flag to pull command (#1078)
thevilledev Mar 1, 2025
5ae180f
docs: clarify --trace flag behavior with --output flag (#1060)
thevilledev Mar 1, 2025
4435c65
fix: Conftest can now successfully load files using a file URL (e.g.…
pckvcode Mar 1, 2025
39bd5fc
ci: Revert "replace Makefile-based Docker builds with GitHub Action… …
jalseth Mar 1, 2025
a20159b
build(deps): bump github.com/moby/buildkit from 0.20.0 to 0.20.1 (#1083)
dependabot[bot] Mar 7, 2025
6a9a474
docs: add documentation feature to the navigation bar (#1087)
boranx Mar 14, 2025
21e1163
feat: add pre-commit hook support (#1077)
thevilledev Mar 20, 2025
1b1ce3a
build(deps): bump golang from 1.24.0-alpine to 1.24.1-alpine (#1086)
dependabot[bot] Mar 20, 2025
45bf533
build(deps): bump github.com/BurntSushi/toml from 1.4.0 to 1.5.0 (#1089)
dependabot[bot] Mar 20, 2025
8c8b13f
ci: Remove PR workflow access to all permissions from GITHUB_TOKEN (#…
jalseth Mar 23, 2025
32aac49
build(deps): bump github.com/moby/buildkit from 0.20.1 to 0.20.2 (#1091)
dependabot[bot] Mar 30, 2025
eac6f5e
build(deps): bump github.com/open-policy-agent/opa from 1.2.0 to 1.3.…
dependabot[bot] Mar 30, 2025
cb88a17
build(deps): bump golang from 1.24.1-alpine to 1.24.2-alpine (#1096)
dependabot[bot] Apr 8, 2025
813f329
build(deps): bump cuelang.org/go from 0.12.0 to 0.12.1 (#1094)
dependabot[bot] Apr 8, 2025
19f1eaf
build(deps): bump github.com/magiconair/properties from 1.8.9 to 1.8.…
dependabot[bot] Apr 12, 2025
688c88f
deps: Bump hcl2json to v0.6.7 (#1074)
jalseth Apr 12, 2025
e9612c3
refactor(ci): replace Makefile-based Docker builds with GitHub Action…
Amamgbu Apr 12, 2025
7bec660
docs: update default template link to use absolute URL (#1099)
thevilledev Apr 19, 2025
3ae2e78
chore: Update Github Actions via Dependabot (#1100)
mrueg Apr 19, 2025
b3d0491
build(deps): bump golangci/golangci-lint-action from 6 to 7 (#1103)
dependabot[bot] Apr 20, 2025
67a3c3e
build(deps): bump actions/setup-go from 4 to 5 (#1102)
dependabot[bot] Apr 20, 2025
609490f
build(deps): bump bats-core/bats-action from 1.5.4 to 3.0.1 (#1104)
dependabot[bot] Apr 20, 2025
4c5e5f5
ci: Move docker build to separate job in the PR workflow (#1105)
jalseth Apr 24, 2025
18a0f14
feat(runner): add support for symlinks (#1098)
Apr 26, 2025
06658d4
feat(output): redirect trace output to stderr (#1084)
thevilledev Apr 26, 2025
5ea0446
build(deps): bump github.com/moby/buildkit from 0.20.2 to 0.21.0 (#1101)
dependabot[bot] Apr 26, 2025
21a73eb
build(deps): bump github.com/moby/buildkit from 0.21.0 to 0.21.1 (#1111)
dependabot[bot] May 4, 2025
2797c99
build(deps): bump github.com/open-policy-agent/opa from 1.3.0 to 1.4.…
dependabot[bot] May 4, 2025
c0799c4
docs: Make examples in the docs compatible with v1 syntax (#1115)
jalseth May 7, 2025
3907482
cli: Make Rego v1 syntax the default (#1114)
jalseth May 7, 2025
e894c43
build(deps): bump golangci/golangci-lint-action from 7 to 8 (#1119)
dependabot[bot] May 7, 2025
9e56924
build(deps): bump github.com/google/go-jsonnet from 0.20.0 to 0.21.0 …
dependabot[bot] May 9, 2025
1441245
docs: Update README.md to make it compatible with v1 syntax (#1122)
IshentRas May 10, 2025
1fe40dd
Merge remote-tracking branch 'upstream/master'
janmooij May 16, 2025
03ff170
Merge remote-tracking branch 'upstream/master' into janmooij/v0.60.0
janmooij May 16, 2025
c50d866
fix: revert makefile changes
janmooij May 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat: Implement SARIF output (open-policy-agent#1042)
* feat: add SARIF output format support

Add Static Analysis Results Interchange Format (SARIF) v2.1.0 output support
to conftest. SARIF is a standard JSON format for static analysis tools.

- SARIF v2.1.0 schema compliance
- Includes file locations and rule metadata
- Tracks execution timing and status
- Test coverage
- Documentation

Signed-off-by: Ville Vesilehto <[email protected]>

* feat(output): implement SARIF output using go-sarif library

Add Static Analysis Results Interchange Format (SARIF) v2.1.0 output support
using the go-sarif library. This provides a standard JSON format for static
analysis results with proper schema compliance.

Key changes:
- Use go-sarif/v2 library instead of custom implementation
- Support all result types (failures, warnings, exceptions, successes)
- Add comprehensive test coverage with JSON comparison
- Document new output format in options.md

The SARIF output includes:
- File locations and rule metadata
- Proper result levels (error/warning/note/none)
- Execution status and exit codes
- Rule properties from result metadata

Signed-off-by: Ville Vesilehto <[email protected]>

* refactor: address pr comments

- refactor: remove getRuleIndex
  Use direct map lookups instead

- refactor: succinct map lookups
  Map lookup with a fallback

- refactor: move result type logic to addResult func
  Cleaner code, while not really idiomatic due to go-sarif
  library design.

- fix: treat exceptions as success
  A file with only exceptions will be treated as a success. Exceptions
  will still be logged (with level "note") for visibility. The exit code
  will be 0 (success) when there are only exceptions.

- refactor: simplify hasFailures and hasWarnings
  Risk of typo is too high

- refactor: treat exceptions as successes in SARIF output
  Exceptions are now treated as successes in the SARIF output, removing
  the separate exception handling.

- test: type safe test input for SARIF
  Probably helps writing further test cases, instead of bare JSON

- refactor: use google/go-cmp for json diff
  Based on PR comment

Signed-off-by: Ville Vesilehto <[email protected]>

---------

Signed-off-by: Ville Vesilehto <[email protected]>
  • Loading branch information
thevilledev authored Feb 15, 2025
commit abad25585b78d45ab896ce836c3477a9c00c77d7
8 changes: 8 additions & 0 deletions docs/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ As of today Conftest supports the following output types:
- JUnit `--output=junit`
- GitHub `--output=github`
- AzureDevOps `--output=azuredevops`
- SARIF `--output=sarif`

### Plaintext

Expand Down Expand Up @@ -322,6 +323,13 @@ success file=examples/kubernetes/deployment.yaml 1
5 tests, 1 passed, 0 warnings, 4 failures, 0 exceptions
```

### SARIF

```console
$ conftest test --proto-file-dirs examples/textproto/protos -p examples/textproto/policy examples/textproto/fail.textproto -o sarif
{"version":"2.1.0","$schema":"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json","runs":[{"tool":{"driver":{"informationUri":"https://github.com/open-policy-agent/conftest","name":"conftest","rules":[{"id":"main/deny","shortDescription":{"text":"Policy violation"}}]}},"invocations":[{"executionSuccessful":true,"exitCode":1,"exitCodeDescription":"Policy violations found"}],"results":[{"ruleId":"main/deny","ruleIndex":0,"level":"error","message":{"text":"fail: Power level must be over 9000"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"examples/textproto/fail.textproto"}}}]}]}]}
```

## `--parser`

Conftest normally detects which parser to used based on the file extension of the file, even when multiple input files are passed in. However, it is possible force a specific parser to be used with the `--parser` flag.
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ require (
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/owenrumney/go-sarif/v2 v2.3.3 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/prometheus/client_golang v1.20.5 // indirect
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1007,6 +1007,10 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/owenrumney/go-sarif v1.1.1 h1:QNObu6YX1igyFKhdzd7vgzmw7XsWN3/6NMGuDzBgXmE=
github.com/owenrumney/go-sarif v1.1.1/go.mod h1:dNDiPlF04ESR/6fHlPyq7gHKmrM0sHUvAGjsoh8ZH0U=
github.com/owenrumney/go-sarif/v2 v2.3.3 h1:ubWDJcF5i3L/EIOER+ZyQ03IfplbSU1BLOE26uKQIIU=
github.com/owenrumney/go-sarif/v2 v2.3.3/go.mod h1:MSqMMx9WqlBSY7pXoOZWgEsVB4FDNfhcaXDA1j6Sr+w=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
Expand Down Expand Up @@ -1146,6 +1150,7 @@ github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
github.com/zclconf/go-cty v1.6.1/go.mod h1:VDR4+I79ubFBGm1uJac1226K5yANQFHeauxPBoP54+o=
github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
github.com/zclconf/go-cty v1.13.2 h1:4GvrUxe/QUDYuJKAav4EYqdM47/kZa672LwmXFmEKT0=
github.com/zclconf/go-cty v1.13.2/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0=
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
Expand Down Expand Up @@ -1871,6 +1876,7 @@ google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1B
google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
Expand Down
4 changes: 4 additions & 0 deletions output/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const (
OutputJUnit = "junit"
OutputGitHub = "github"
OutputAzureDevOps = "azuredevops"
OutputSARIF = "sarif"
)

// Get returns a type that can render output in the given format.
Expand All @@ -57,6 +58,8 @@ func Get(format string, options Options) Outputter {
return NewGitHub(options.File)
case OutputAzureDevOps:
return NewAzureDevOps(options.File)
case OutputSARIF:
return NewSARIF(options.File)
default:
return NewStandard(options.File)
}
Expand All @@ -72,5 +75,6 @@ func Outputs() []string {
OutputJUnit,
OutputGitHub,
OutputAzureDevOps,
OutputSARIF,
}
}
4 changes: 4 additions & 0 deletions output/output_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ func TestGetOutputter(t *testing.T) {
input: OutputAzureDevOps,
expected: NewAzureDevOps(os.Stdout),
},
{
input: OutputSARIF,
expected: NewSARIF(os.Stdout),
},
{
input: "unknown_format",
expected: NewStandard(os.Stdout),
Expand Down
210 changes: 210 additions & 0 deletions output/sarif.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
package output

import (
"fmt"
"io"
"path/filepath"
"strings"

"github.com/open-policy-agent/opa/tester"
"github.com/owenrumney/go-sarif/v2/sarif"
"golang.org/x/exp/slices"
)

const (
// Tool information
toolName = "conftest"
toolURI = "https://github.com/open-policy-agent/conftest"
sarifVersion = sarif.Version210

// Result descriptions
successDesc = "Policy was satisfied successfully"
skippedDesc = "Policy check was skipped"
failureDesc = "Policy violation"
warningDesc = "Policy warning"
exceptionDesc = "Policy exception"

// Exit code descriptions
exitNoViolations = "No policy violations found"
exitViolations = "Policy violations found"
exitWarnings = "Policy warnings found"
)

// SARIF represents an Outputter that outputs results in SARIF format.
type SARIF struct {
writer io.Writer
}

// NewSARIF creates a new SARIF with the given writer.
func NewSARIF(w io.Writer) *SARIF {
return &SARIF{
writer: w,
}
}

// getRuleID generates a stable rule ID based on namespace and rule type
func getRuleID(namespace string, ruleType string) string {
return fmt.Sprintf("%s/%s", namespace, ruleType)
}

// getRuleDescription returns the appropriate description based on the rule type
func getRuleDescription(ruleID string) string {
switch {
case strings.HasSuffix(ruleID, "/success"):
return successDesc
case strings.HasSuffix(ruleID, "/skip"):
return skippedDesc
case strings.HasSuffix(ruleID, "/allow"):
return exceptionDesc
case strings.HasSuffix(ruleID, "/warn"):
return warningDesc
default:
return failureDesc
}
}

// addRuleIndex adds a new rule to the SARIF run and returns its index.
func addRuleIndex(run *sarif.Run, ruleID string, result Result, indices map[string]int) int {
addRule(run, ruleID, result)
idx := len(run.Tool.Driver.Rules) - 1
indices[ruleID] = idx
return idx
}

// addRule adds a new rule to the SARIF run with the given ID and result metadata.
func addRule(run *sarif.Run, ruleID string, result Result) {
desc := getRuleDescription(ruleID)
rule := run.AddRule(ruleID).
WithDescription(desc).
WithShortDescription(&sarif.MultiformatMessageString{
Text: &desc,
})

if result.Metadata != nil {
props := sarif.NewPropertyBag()
for k, v := range result.Metadata {
props.Add(k, v)
}
rule.WithProperties(props.Properties)
}
}

// addResult adds a result to the SARIF run
func addResult(run *sarif.Run, result Result, namespace, ruleType, level, fileName string, indices map[string]int) {
ruleID := getRuleID(namespace, ruleType)
idx, ok := indices[ruleID]
if !ok {
idx = addRuleIndex(run, ruleID, result, indices)
}

run.CreateResultForRule(ruleID).
WithRuleIndex(idx).
WithLevel(level).
WithMessage(sarif.NewTextMessage(result.Message)).
AddLocation(
sarif.NewLocationWithPhysicalLocation(
sarif.NewPhysicalLocation().
WithArtifactLocation(
sarif.NewSimpleArtifactLocation(filepath.ToSlash(fileName)),
),
),
)
}

// Output outputs the results in SARIF format.
func (s *SARIF) Output(results []CheckResult) error {
report, err := sarif.New(sarifVersion)
if err != nil {
return fmt.Errorf("create sarif report: %w", err)
}

run := sarif.NewRunWithInformationURI(toolName, toolURI)
indices := make(map[string]int)

for _, result := range results {
// Process failures
for _, failure := range result.Failures {
addResult(run, failure, result.Namespace, "deny", "error", result.FileName, indices)
}

// Process warnings
for _, warning := range result.Warnings {
addResult(run, warning, result.Namespace, "warn", "warning", result.FileName, indices)
}

// Process exceptions (treated as successes)
hasSuccesses := result.Successes > 0
for _, exception := range result.Exceptions {
addResult(run, exception, result.Namespace, "allow", "note", result.FileName, indices)
hasSuccesses = true
}

// Don't add success/skip results if there are failures or warnings
hasErrors := len(result.Failures) > 0 || len(result.Warnings) > 0
if hasErrors {
continue
}

// Add success/exception results if there are no failures or warnings
if hasSuccesses {
statusResult := Result{
Message: successDesc,
Metadata: map[string]interface{}{
"description": successDesc,
},
}
addResult(run, statusResult, result.Namespace, "success", "none", result.FileName, indices)
} else {
statusResult := Result{
Message: skippedDesc,
Metadata: map[string]interface{}{
"description": skippedDesc,
},
}
addResult(run, statusResult, result.Namespace, "skip", "none", result.FileName, indices)
}
}

// Add run metadata
exitCode := 0
exitDesc := exitNoViolations
if hasFailures(results) {
exitCode = 1
exitDesc = exitViolations
} else if hasWarnings(results) {
exitDesc = exitWarnings
}

successful := true
invocation := sarif.NewInvocation()
invocation.ExecutionSuccessful = &successful
invocation.ExitCode = &exitCode
invocation.ExitCodeDescription = &exitDesc

run.Invocations = []*sarif.Invocation{invocation}

// Add the run to the report
report.AddRun(run)

// Write the report
return report.Write(s.writer)
}

// Report is not supported in SARIF output
func (s *SARIF) Report(_ []*tester.Result, _ string) error {
return fmt.Errorf("report is not supported in SARIF output")
}

// hasFailures returns true if any of the results contain failures
func hasFailures(results []CheckResult) bool {
return slices.ContainsFunc(results, func(r CheckResult) bool {
return len(r.Failures) > 0
})
}

// hasWarnings returns true if any of the results contain warnings
func hasWarnings(results []CheckResult) bool {
return slices.ContainsFunc(results, func(r CheckResult) bool {
return len(r.Warnings) > 0
})
}
Loading
Loading