Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
28 changes: 26 additions & 2 deletions opa/rego/poutine/queries/findings.rego
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,29 @@ import rego.v1

rules_by_id[id] = rules[id].rule

_purl_match(finding_purl, skip_purl) if {
finding_purl == skip_purl
}

# Prefix match with structural purl boundary: ensures that e.g.
# "pkg:githubactions/foo/bar" matches "pkg:githubactions/foo/bar@v1"
# (boundary is @) but not "pkg:githubactions/foo/bar-baz@v1".
_purl_match(finding_purl, skip_purl) if {
startswith(finding_purl, skip_purl)
rest := substring(finding_purl, count(skip_purl), -1)
regex.match("^[@#]", rest)
}

# No purl constraint in skip rule: purl matches by default.
_skip_purl(_, s) if {
not s.purl
}

_skip_purl(o, s) if {
skip_purl := s.purl[_]
_purl_match(o.purl, skip_purl)
}

skip(f) if {
s := data.config.skip[_]
o := object.union(
Expand All @@ -13,11 +36,12 @@ skip(f) if {
"rule": f.rule_id,
"level": rules_by_id[rule_id].level,
},
object.filter(f.meta, {"osv_id", "job", "path"}),
object.filter(f.meta, {"osv_id", "job", "path", "purl"}),
)

count(s) > 0
[attr | s[attr]; not o[attr] in s[attr]] == []
[attr | s[attr]; attr != "purl"; not o[attr] in s[attr]] == []
_skip_purl(o, s)
}

skip(f) if {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ results contains poutine.finding(rule, pkg.purl, {
"job": job.id,
"step": i,
"details": step.uses,
"purl": dep,
"event_triggers": [event | event := workflow.events[j].name],
}) if {
pkg := input.packages[_]
Expand All @@ -39,6 +40,7 @@ results contains poutine.finding(rule, pkg.purl, {
"line": step.lines.uses,
"step": i,
"details": step.uses,
"purl": dep,
}) if {
pkg := input.packages[_]
action := pkg.github_actions_metadata[_]
Expand Down
96 changes: 88 additions & 8 deletions scanner/inventory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func TestPurls(t *testing.T) {
}
_ = pkg.NormalizePurl()
scannedPackage, err := i.ScanPackage(context.Background(), *pkg, "testdata")
assert.NoError(t, err)
require.NoError(t, err)

purls := []string{
"pkg:docker/node%3Alatest",
Expand Down Expand Up @@ -74,7 +74,7 @@ func TestFindings(t *testing.T) {
_ = pkg.NormalizePurl()

scannedPackage, err := i.ScanPackage(context.Background(), *pkg, "testdata")
assert.NoError(t, err)
require.NoError(t, err)

analysisResults := scannedPackage.FindingsResults

Expand Down Expand Up @@ -700,7 +700,7 @@ func TestSkipRule(t *testing.T) {
_ = pkg.NormalizePurl()

updatedPkg, err := i.ScanPackage(ctx, *pkg, "testdata")
assert.NoError(t, err)
require.NoError(t, err)

analysisResults := updatedPkg.FindingsResults

Expand All @@ -718,10 +718,10 @@ func TestSkipRule(t *testing.T) {
},
},
})
assert.NoError(t, err)
require.NoError(t, err)

secondUpdatedPkg, err := i.ScanPackage(context.Background(), *pkg, "testdata")
assert.NoError(t, err)
require.NoError(t, err)

analysisResults = secondUpdatedPkg.FindingsResults

Expand All @@ -733,6 +733,86 @@ func TestSkipRule(t *testing.T) {
assert.NotContains(t, rule_ids, rule_id)
}

func TestSkipRuleByActionPurl(t *testing.T) {
o, _ := opa.NewOpa(context.TODO(), &models.Config{
Include: []models.ConfigInclude{},
})
i := NewInventory(o, nil, "", "")
ctx := context.TODO()
purl := "pkg:github/org/owner"
rule_id := "github_action_from_unverified_creator_used"
pkg := &models.PackageInsights{
Purl: purl,
SourceGitRepo: "org/owner",
SourceGitRef: "main",
}
_ = pkg.NormalizePurl()

updatedPkg, err := i.ScanPackage(ctx, *pkg, "testdata")
require.NoError(t, err)

// Collect findings for the unverified creator rule
var unverifiedFindings []results.Finding
for _, f := range updatedPkg.FindingsResults.Findings {
if f.RuleId == rule_id {
unverifiedFindings = append(unverifiedFindings, f)
}
}
require.NotEmpty(t, unverifiedFindings, "expected unverified creator findings before skip")

// Test 1: Versionless skip should match ALL versions of kartverket/github-workflows
err = o.WithConfig(ctx, &models.Config{
Skip: []models.ConfigSkip{
{
Rule: []string{rule_id},
Purl: []string{"pkg:githubactions/kartverket/github-workflows"},
},
},
})
require.NoError(t, err)

secondUpdatedPkg, err := i.ScanPackage(context.Background(), *pkg, "testdata")
require.NoError(t, err)

for _, f := range secondUpdatedPkg.FindingsResults.Findings {
if f.RuleId == rule_id {
assert.NotContains(t, f.Meta.Details, "kartverket/github-workflows",
"versionless skip should remove all versions of kartverket/github-workflows")
}
}

// Test 2: Version-specific skip should only match that exact version
err = o.WithConfig(ctx, &models.Config{
Skip: []models.ConfigSkip{
{
Rule: []string{rule_id},
Purl: []string{"pkg:githubactions/kartverket/github-workflows@v2.7.1"},
},
},
})
require.NoError(t, err)

thirdUpdatedPkg, err := i.ScanPackage(context.Background(), *pkg, "testdata")
require.NoError(t, err)

var remainingDetails []string
for _, f := range thirdUpdatedPkg.FindingsResults.Findings {
if f.RuleId == rule_id {
remainingDetails = append(remainingDetails, f.Meta.Details)
}
}
// v2.7.1 should be skipped, but @main and @v2.2 should remain
for _, d := range remainingDetails {
assert.NotContains(t, d, "@v2.7.1",
"version-specific skip should remove only that version")
}
// Verify other versions are still present
assert.Contains(t, remainingDetails, "kartverket/github-workflows/.github/workflows/run-terraform.yml@main",
"@main should not be skipped by version-specific skip")
assert.Contains(t, remainingDetails, "kartverket/github-workflows/.github/workflows/run-terraform.yml@v2.2",
"@v2.2 should not be skipped by version-specific skip")
}

func TestRulesConfig(t *testing.T) {
o, _ := opa.NewOpa(context.TODO(), &models.Config{
Include: []models.ConfigInclude{},
Expand All @@ -750,7 +830,7 @@ func TestRulesConfig(t *testing.T) {
_ = pkg.NormalizePurl()

scannedPackage, err := i.ScanPackage(ctx, *pkg, "testdata")
assert.NoError(t, err)
require.NoError(t, err)

labels := []string{}
for _, f := range scannedPackage.FindingsResults.Findings {
Expand All @@ -767,10 +847,10 @@ func TestRulesConfig(t *testing.T) {
},
},
})
assert.NoError(t, err)
require.NoError(t, err)

reScannedPackage, err := i.ScanPackage(ctx, *pkg, "testdata")
assert.NoError(t, err)
require.NoError(t, err)

labels = []string{}
for _, f := range reScannedPackage.FindingsResults.Findings {
Expand Down
Loading