fix(k8s): disable parallel traversal with fs cache for k8s images (#9534)

This commit is contained in:
afdesk
2025-09-30 07:44:51 +06:00
committed by GitHub
parent bfd2f6ba69
commit c0c7a6bf1b
4 changed files with 349 additions and 21 deletions

View File

@@ -6,6 +6,7 @@ import (
"encoding/json"
"os"
"path/filepath"
"sort"
"testing"
cdx "github.com/CycloneDX/cyclonedx-go"
@@ -28,19 +29,14 @@ func TestK8s(t *testing.T) {
outputFile := filepath.Join(t.TempDir(), "output.json")
osArgs := []string{
"--cache-dir",
cacheDir,
"--cache-dir", cacheDir,
"k8s",
"kind-kind-test",
"--report",
"summary",
"--report", "summary",
"-q",
"--timeout",
"5m0s",
"--format",
"json",
"--output",
outputFile,
"--timeout", "5m0s",
"--format", "json",
"--output", outputFile,
}
// Run Trivy
@@ -60,15 +56,47 @@ func TestK8s(t *testing.T) {
return resource.Results
})
// Has vulnerabilities
assert.True(t, lo.SomeBy(results, func(r types.Result) bool {
return len(r.Vulnerabilities) > 0
}))
// Collect IDs (CVEs for vulns, IDs for failed misconfigs), allowing duplicates.
ids := k8sFindingIDs{}
for _, r := range results {
for _, v := range r.Vulnerabilities {
if v.VulnerabilityID != "" {
ids.Vulnerabilities = append(ids.Vulnerabilities, v.VulnerabilityID)
}
}
for _, m := range r.Misconfigurations {
if m.Status == types.MisconfStatusFailure && m.ID != "" {
ids.Misconfigurations = append(ids.Misconfigurations, m.ID)
}
}
}
// Has misconfigurations
assert.True(t, lo.SomeBy(results, func(r types.Result) bool {
return len(r.Misconfigurations) > 0
}))
// Sort for deterministic golden files
sort.Strings(ids.Vulnerabilities)
sort.Strings(ids.Misconfigurations)
fixture := filepath.Join("testdata", "fixtures", "k8s", "summary-ids.json.golden")
if *update {
// Update fixture with current IDs (duplicates kept, sorted)
// Note: mage test:k8s may create additional k8s artifacts.
f, err := os.Create(fixture)
require.NoError(t, err)
defer f.Close()
enc := json.NewEncoder(f)
enc.SetIndent("", " ")
require.NoError(t, enc.Encode(ids))
t.Logf("updated fixture: %s", fixture)
return
}
// Read expected IDs from fixture and compare
ef, err := os.Open(fixture)
require.NoError(t, err)
defer ef.Close()
var want k8sFindingIDs
require.NoError(t, json.NewDecoder(ef).Decode(&want))
assert.Equal(t, want, ids)
})
t.Run("kbom cycloneDx", func(t *testing.T) {
// Set up the output file
@@ -106,7 +134,6 @@ func TestK8s(t *testing.T) {
return len(*r.Dependencies) > 0
}))
})
t.Run("limited user test", func(t *testing.T) {
// Set up the output file
outputFile := filepath.Join(t.TempDir(), "output.json")
@@ -158,3 +185,9 @@ func TestK8s(t *testing.T) {
})
}
// k8sFindingIDs is the structure saved into the golden file.
type k8sFindingIDs struct {
Vulnerabilities []string `json:"vulnerabilities"`
Misconfigurations []string `json:"misconfigurations"`
}

View File

@@ -0,0 +1,290 @@
{
"vulnerabilities": [
"CVE-2019-1551",
"CVE-2019-1551",
"CVE-2019-1563",
"CVE-2019-1563",
"CVE-2019-18276",
"CVE-2019-18276",
"CVE-2019-5094",
"CVE-2019-5094",
"CVE-2019-5094",
"CVE-2019-5094",
"CVE-2019-5094",
"CVE-2019-5094",
"CVE-2019-5094",
"CVE-2019-5094"
],
"misconfigurations": [
"AVD-KSV-01010",
"KCV0001",
"KCV0006",
"KCV0010",
"KCV0018",
"KCV0019",
"KCV0020",
"KCV0021",
"KCV0022",
"KCV0030",
"KCV0033",
"KCV0038",
"KCV0059",
"KCV0069",
"KCV0075",
"KCV0077",
"KSV001",
"KSV001",
"KSV001",
"KSV001",
"KSV001",
"KSV001",
"KSV001",
"KSV001",
"KSV001",
"KSV0012",
"KSV003",
"KSV003",
"KSV003",
"KSV003",
"KSV003",
"KSV003",
"KSV003",
"KSV003",
"KSV003",
"KSV004",
"KSV004",
"KSV004",
"KSV004",
"KSV004",
"KSV004",
"KSV004",
"KSV004",
"KSV004",
"KSV009",
"KSV009",
"KSV009",
"KSV009",
"KSV009",
"KSV009",
"KSV011",
"KSV011",
"KSV011",
"KSV011",
"KSV011",
"KSV011",
"KSV011",
"KSV011",
"KSV011",
"KSV012",
"KSV012",
"KSV012",
"KSV012",
"KSV012",
"KSV012",
"KSV012",
"KSV012",
"KSV012",
"KSV012",
"KSV0125",
"KSV0125",
"KSV0125",
"KSV0125",
"KSV0125",
"KSV0125",
"KSV0125",
"KSV0125",
"KSV014",
"KSV014",
"KSV014",
"KSV014",
"KSV014",
"KSV014",
"KSV014",
"KSV014",
"KSV014",
"KSV015",
"KSV015",
"KSV015",
"KSV015",
"KSV016",
"KSV016",
"KSV016",
"KSV016",
"KSV016",
"KSV016",
"KSV016",
"KSV017",
"KSV018",
"KSV018",
"KSV018",
"KSV018",
"KSV018",
"KSV018",
"KSV018",
"KSV018",
"KSV020",
"KSV020",
"KSV020",
"KSV020",
"KSV020",
"KSV020",
"KSV020",
"KSV020",
"KSV020",
"KSV020",
"KSV021",
"KSV021",
"KSV021",
"KSV021",
"KSV021",
"KSV021",
"KSV021",
"KSV021",
"KSV021",
"KSV021",
"KSV022",
"KSV022",
"KSV023",
"KSV023",
"KSV023",
"KSV023",
"KSV023",
"KSV023",
"KSV030",
"KSV030",
"KSV030",
"KSV030",
"KSV030",
"KSV030",
"KSV036",
"KSV041",
"KSV041",
"KSV041",
"KSV041",
"KSV041",
"KSV041",
"KSV041",
"KSV041",
"KSV041",
"KSV041",
"KSV041",
"KSV041",
"KSV041",
"KSV044",
"KSV045",
"KSV046",
"KSV046",
"KSV046",
"KSV046",
"KSV046",
"KSV046",
"KSV046",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV048",
"KSV049",
"KSV049",
"KSV049",
"KSV049",
"KSV049",
"KSV049",
"KSV049",
"KSV049",
"KSV050",
"KSV050",
"KSV053",
"KSV053",
"KSV053",
"KSV056",
"KSV056",
"KSV056",
"KSV056",
"KSV056",
"KSV056",
"KSV056",
"KSV056",
"KSV056",
"KSV056",
"KSV056",
"KSV056",
"KSV056",
"KSV056",
"KSV056",
"KSV056",
"KSV056",
"KSV056",
"KSV056",
"KSV104",
"KSV104",
"KSV104",
"KSV104",
"KSV104",
"KSV104",
"KSV106",
"KSV106",
"KSV106",
"KSV106",
"KSV106",
"KSV106",
"KSV106",
"KSV106",
"KSV106",
"KSV110",
"KSV111",
"KSV112",
"KSV112",
"KSV113",
"KSV113",
"KSV117",
"KSV117",
"KSV117",
"KSV118",
"KSV118",
"KSV118",
"KSV118",
"KSV118",
"KSV118",
"KSV118",
"KSV118",
"KSV118",
"KSV119",
"KSV122",
"no-user-pods-in-system-namespace",
"no-user-pods-in-system-namespace",
"no-user-pods-in-system-namespace",
"no-user-pods-in-system-namespace"
]
}

View File

@@ -227,7 +227,7 @@ func (t Test) Integration() error {
// K8s runs k8s integration tests
func (t Test) K8s() error {
mg.Deps(Tool{}.Install) // Install kind
err := sh.RunWithV(ENV, "kind", "create", "cluster", "--name", "kind-test")
err := sh.RunWithV(ENV, "kind", "create", "cluster", "--name", "kind-test", "--image", "kindest/node:v1.27.1@sha256:b7d12ed662b873bd8510879c1846e87c7e676a79fefc93e17b2a52989d3ff42b")
if err != nil {
return err
}

View File

@@ -120,8 +120,13 @@ func (s *Scanner) Scan(ctx context.Context, artifactsData []*artifacts.Artifact)
resources = append(resources, result...)
return nil
}
workers := s.opts.Parallel
if s.opts.CacheBackend == string(cache.TypeFS) {
// To avoid lock contention in bbolt, we limit the number of workers to 1 when using FS cache.
workers = 1
}
p := parallel.NewPipeline(s.opts.Parallel, !s.opts.Quiet, resourceArtifacts, onItem, onResult)
p := parallel.NewPipeline(workers, !s.opts.Quiet, resourceArtifacts, onItem, onResult)
if err := p.Do(ctx); err != nil {
return report.Report{}, err
}