Skip to content

Commit 5a5cc73

Browse files
committed
test(seal): add tests for lookupVendor and AllowLocalSpecifier; add EXPERIMENTAL to docs
- Add unit tests for lookupVendor() covering all Seal ecosystems and non-Seal fallback - Add tests for pep440.AllowLocalSpecifier demonstrating strict local version matching - Add EXPERIMENTAL warning to Application Dependencies section in seal.md
1 parent 30cc2d6 commit 5a5cc73

3 files changed

Lines changed: 153 additions & 0 deletions

File tree

docs/guide/coverage/others/seal.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ For details on supported scanners, features, and behavior for each base OS, refe
3131

3232
## Application Dependencies
3333

34+
!!! warning "EXPERIMENTAL"
35+
Scanning results may be inaccurate.
36+
3437
Seal also provides patched versions of application dependencies with their own vulnerability advisories. Trivy automatically detects Seal-patched packages based on special naming patterns specific to each ecosystem.
3538

3639
### Supported Ecosystems

pkg/detector/library/compare/pep440/compare_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,67 @@ func TestPep440Comparer_IsVulnerable(t *testing.T) {
114114
})
115115
}
116116
}
117+
118+
func TestPep440Comparer_AllowLocalSpecifier(t *testing.T) {
119+
type args struct {
120+
currentVersion string
121+
advisory dbTypes.Advisory
122+
}
123+
tests := []struct {
124+
name string
125+
allowLocalSpec bool
126+
args args
127+
want bool
128+
}{
129+
{
130+
// Without AllowLocalSpecifier, the local segment is stripped from the candidate version,
131+
// so "4.2.8+sp1" matches "== 4.2.8" and is incorrectly treated as vulnerable.
132+
name: "without AllowLocalSpecifier: local segment ignored, version matches base constraint",
133+
allowLocalSpec: false,
134+
args: args{
135+
currentVersion: "4.2.8+sp1",
136+
advisory: dbTypes.Advisory{
137+
VulnerableVersions: []string{"== 4.2.8"},
138+
PatchedVersions: []string{"== 4.2.9"},
139+
},
140+
},
141+
want: true,
142+
},
143+
{
144+
// With AllowLocalSpecifier, the local segment is compared strictly,
145+
// so "4.2.8+sp999" does not fall in ">= sp1, < sp999" and is correctly not vulnerable.
146+
name: "with AllowLocalSpecifier: patched version not vulnerable",
147+
allowLocalSpec: true,
148+
args: args{
149+
currentVersion: "4.2.8+sp999",
150+
advisory: dbTypes.Advisory{
151+
VulnerableVersions: []string{">= 4.2.8+sp1, < 4.2.8+sp999"},
152+
PatchedVersions: []string{"4.2.8+sp999"},
153+
},
154+
},
155+
want: false,
156+
},
157+
{
158+
name: "with AllowLocalSpecifier: vulnerable version matched by local range",
159+
allowLocalSpec: true,
160+
args: args{
161+
currentVersion: "4.2.8+sp1",
162+
advisory: dbTypes.Advisory{
163+
VulnerableVersions: []string{">= 4.2.8+sp1, < 4.2.8+sp999"},
164+
PatchedVersions: []string{"4.2.8+sp999"},
165+
},
166+
},
167+
want: true,
168+
},
169+
}
170+
for _, tt := range tests {
171+
t.Run(tt.name, func(t *testing.T) {
172+
var c pep440.Comparer
173+
if tt.allowLocalSpec {
174+
c = pep440.NewComparer(pep440.AllowLocalSpecifier())
175+
}
176+
got := c.IsVulnerable(tt.args.currentVersion, tt.args.advisory)
177+
assert.Equal(t, tt.want, got)
178+
})
179+
}
180+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package library
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
8+
"github.com/aquasecurity/trivy-db/pkg/ecosystem"
9+
"github.com/aquasecurity/trivy/pkg/detector/library/compare"
10+
"github.com/aquasecurity/trivy/pkg/detector/library/compare/pep440"
11+
)
12+
13+
func Test_lookupVendor(t *testing.T) {
14+
defaultComparer := compare.GenericComparer{}
15+
16+
tests := []struct {
17+
name string
18+
eco ecosystem.Type
19+
pkgName string
20+
wantPrefix string
21+
wantComparerNil bool // true if the default comparer should be returned unchanged
22+
}{
23+
{
24+
name: "seal pip package returns vendor prefix and pep440 comparer",
25+
eco: ecosystem.Pip,
26+
pkgName: "seal-requests",
27+
wantPrefix: "seal pip::",
28+
wantComparerNil: false,
29+
},
30+
{
31+
name: "seal npm package returns vendor prefix and default comparer",
32+
eco: ecosystem.Npm,
33+
pkgName: "@seal-security/ejs",
34+
wantPrefix: "seal npm::",
35+
wantComparerNil: true,
36+
},
37+
{
38+
name: "seal go package returns vendor prefix and default comparer",
39+
eco: ecosystem.Go,
40+
pkgName: "sealsecurity.io/github.com/foo/bar",
41+
wantPrefix: "seal go::",
42+
wantComparerNil: true,
43+
},
44+
{
45+
name: "seal maven package returns vendor prefix and default comparer",
46+
eco: ecosystem.Maven,
47+
pkgName: "seal.sp1.org.eclipse.jetty:jetty-http",
48+
wantPrefix: "seal maven::",
49+
wantComparerNil: true,
50+
},
51+
{
52+
name: "seal rubygems package returns vendor prefix and default comparer",
53+
eco: ecosystem.RubyGems,
54+
pkgName: "seal-rack",
55+
wantPrefix: "seal rubygems::",
56+
wantComparerNil: true,
57+
},
58+
{
59+
name: "non-seal pip package returns standard prefix",
60+
eco: ecosystem.Pip,
61+
pkgName: "requests",
62+
wantPrefix: "pip::",
63+
wantComparerNil: true,
64+
},
65+
{
66+
name: "non-seal npm package returns standard prefix",
67+
eco: ecosystem.Npm,
68+
pkgName: "ejs",
69+
wantPrefix: "npm::",
70+
wantComparerNil: true,
71+
},
72+
}
73+
74+
for _, tt := range tests {
75+
t.Run(tt.name, func(t *testing.T) {
76+
gotPrefix, gotComparer := lookupVendor(tt.eco, tt.pkgName, "", defaultComparer)
77+
assert.Equal(t, tt.wantPrefix, gotPrefix)
78+
if tt.wantComparerNil {
79+
assert.Equal(t, defaultComparer, gotComparer)
80+
} else {
81+
// For seal pip, a custom pep440 comparer with AllowLocalSpecifier should be returned.
82+
assert.IsType(t, pep440.Comparer{}, gotComparer)
83+
}
84+
})
85+
}
86+
}

0 commit comments

Comments
 (0)