Skip to content

Commit f18d035

Browse files
stringbeanknqyf263
andauthored
feat(java): add support for sbt projects using sbt-dependency-lock (#6882)
Signed-off-by: knqyf263 <[email protected]> Co-authored-by: knqyf263 <[email protected]>
1 parent 1f8fca1 commit f18d035

File tree

22 files changed

+687
-5
lines changed

22 files changed

+687
-5
lines changed

docs/docs/configuration/reporting.md

+2
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ The following languages are currently supported:
6464
| PHP | [composer.lock][composer-lock] |
6565
| Java | [pom.xml][pom-xml] |
6666
| | [*gradle.lockfile][gradle-lockfile] |
67+
| | [*.sbt.lock][sbt-lockfile] |
6768
| Dart | [pubspec.lock][pubspec-lock] |
6869

6970
This tree is the reverse of the dependency graph.
@@ -447,5 +448,6 @@ $ trivy convert --format table --severity CRITICAL result.json
447448
[composer-lock]: ../coverage/language/php.md#composer
448449
[pom-xml]: ../coverage/language/java.md#pomxml
449450
[gradle-lockfile]: ../coverage/language/java.md#gradlelock
451+
[sbt-lockfile]: ../coverage/language/java.md#sbt
450452
[pubspec-lock]: ../coverage/language/dart.md#dart
451453
[cargo-binaries]: ../coverage/language/rust.md#binaries

docs/docs/coverage/language/index.md

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ On the other hand, when the target is a post-build artifact, like a container im
3838
| [Java](java.md) | JAR/WAR/PAR/EAR[^4] ||| - | - |
3939
| | pom.xml | - | - |||
4040
| | *gradle.lockfile | - | - |||
41+
| | *.sbt.lock | - | - |||
4142
| [Go](golang.md) | Binaries built by Go ||| - | - |
4243
| | go.mod | - | - |||
4344
| [Rust](rust.md) | Cargo.lock |||||

docs/docs/coverage/language/java.md

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Java
2-
Trivy supports three types of Java scanning: `JAR/WAR/PAR/EAR`, `pom.xml` and `*gradle.lockfile` files.
2+
Trivy supports four types of Java scanning: `JAR/WAR/PAR/EAR`, `pom.xml`, `*gradle.lockfile` and `*.sbt.lock` files.
33

44
Each artifact supports the following scanners:
55

@@ -8,6 +8,7 @@ Each artifact supports the following scanners:
88
| JAR/WAR/PAR/EAR ||| - |
99
| pom.xml ||||
1010
| *gradle.lockfile ||||
11+
| *.sbt.lock ||| - |
1112

1213
The following table provides an outline of the features Trivy offers.
1314

@@ -16,6 +17,7 @@ The following table provides an outline of the features Trivy offers.
1617
| JAR/WAR/PAR/EAR | Trivy Java DB | Include | - | - |
1718
| pom.xml | Maven repository [^1] | Exclude ||[^7] |
1819
| *gradle.lockfile | - | Exclude |||
20+
| *.sbt.lock | - | Exclude | - ||
1921

2022
These may be enabled or disabled depending on the target.
2123
See [here](./index.md) for the detail.
@@ -94,6 +96,15 @@ Trity also can detect licenses for dependencies.
9496

9597
Make sure that you have cache[^8] directory to find licenses from `*.pom` dependency files.
9698

99+
100+
## SBT
101+
102+
`build.sbt.lock` files only contain information about used dependencies. This requires a lockfile generated using the
103+
[sbt-dependency-lock][sbt-dependency-lock] plugin.
104+
105+
!!!note
106+
All necessary files are checked locally. SBT file scanning doesn't require internet access.
107+
97108
[^1]: Uses maven repository to get information about dependencies. Internet access required.
98109
[^2]: It means `*.jar`, `*.war`, `*.par` and `*.ear` file
99110
[^3]: `ArtifactID`, `GroupID` and `Version`
@@ -106,4 +117,5 @@ Make sure that you have cache[^8] directory to find licenses from `*.pom` depend
106117
[dependency-graph]: ../../configuration/reporting.md#show-origins-of-vulnerable-dependencies
107118
[maven-invoker-plugin]: https://maven.apache.org/plugins/maven-invoker-plugin/usage.html
108119
[maven-central]: https://repo.maven.apache.org/maven2/
109-
[maven-pom-repos]: https://maven.apache.org/settings.html#repositories
120+
[maven-pom-repos]: https://maven.apache.org/settings.html#repositories
121+
[sbt-dependency-lock]: https://stringbean.github.io/sbt-dependency-lock

integration/repo_test.go

+8
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,14 @@ func TestRepository(t *testing.T) {
153153
},
154154
golden: "testdata/gradle.json.golden",
155155
},
156+
{
157+
name: "sbt",
158+
args: args{
159+
scanner: types.VulnerabilityScanner,
160+
input: "testdata/fixtures/repo/sbt",
161+
},
162+
golden: "testdata/sbt.json.golden",
163+
},
156164
{
157165
name: "conan",
158166
args: args{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"lockVersion" : 1,
3+
"timestamp" : "2024-06-06T11:03:09.964557Z",
4+
"configurations" : [
5+
"compile",
6+
"optional",
7+
"provided",
8+
"runtime",
9+
"test"
10+
],
11+
"dependencies" : [
12+
{
13+
"org" : "com.fasterxml.jackson.core",
14+
"name" : "jackson-databind",
15+
"version" : "2.9.1",
16+
"artifacts" : [
17+
{
18+
"name" : "jackson-databind.jar",
19+
"hash" : "sha1:716da1830a2043f18882fc036ec26eb32cbe5aff"
20+
}
21+
],
22+
"configurations" : [
23+
"compile",
24+
"runtime",
25+
"test"
26+
]
27+
}
28+
]
29+
}

integration/testdata/sbt.json.golden

+149
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
{
2+
"SchemaVersion": 2,
3+
"CreatedAt": "2021-08-25T12:20:30.000000005Z",
4+
"ArtifactName": "testdata/fixtures/repo/sbt",
5+
"ArtifactType": "repository",
6+
"Metadata": {
7+
"ImageConfig": {
8+
"architecture": "",
9+
"created": "0001-01-01T00:00:00Z",
10+
"os": "",
11+
"rootfs": {
12+
"type": "",
13+
"diff_ids": null
14+
},
15+
"config": {}
16+
}
17+
},
18+
"Results": [
19+
{
20+
"Target": "build.sbt.lock",
21+
"Class": "lang-pkgs",
22+
"Type": "sbt",
23+
"Vulnerabilities": [
24+
{
25+
"VulnerabilityID": "CVE-2020-9548",
26+
"PkgID": "com.fasterxml.jackson.core:jackson-databind:2.9.1",
27+
"PkgName": "com.fasterxml.jackson.core:jackson-databind",
28+
"PkgIdentifier": {
29+
"PURL": "pkg:maven/com.fasterxml.jackson.core/[email protected]",
30+
"UID": "9ccd2eb3e03373ff"
31+
},
32+
"InstalledVersion": "2.9.1",
33+
"FixedVersion": "2.9.10.4",
34+
"Status": "fixed",
35+
"Layer": {},
36+
"SeveritySource": "ghsa",
37+
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2020-9548",
38+
"DataSource": {
39+
"ID": "ghsa",
40+
"Name": "GitHub Security Advisory Maven",
41+
"URL": "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Amaven"
42+
},
43+
"Title": "jackson-databind: Serialization gadgets in anteros-core",
44+
"Description": "FasterXML jackson-databind 2.x before 2.9.10.4 mishandles the interaction between serialization gadgets and typing, related to br.com.anteros.dbcp.AnterosDBCPConfig (aka anteros-core).",
45+
"Severity": "CRITICAL",
46+
"CweIDs": [
47+
"CWE-502"
48+
],
49+
"VendorSeverity": {
50+
"ghsa": 4,
51+
"nvd": 4,
52+
"redhat": 3
53+
},
54+
"CVSS": {
55+
"nvd": {
56+
"V2Vector": "AV:N/AC:M/Au:N/C:P/I:P/A:P",
57+
"V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
58+
"V2Score": 6.8,
59+
"V3Score": 9.8
60+
},
61+
"redhat": {
62+
"V3Vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
63+
"V3Score": 8.1
64+
}
65+
},
66+
"References": [
67+
"https://access.redhat.com/security/cve/CVE-2020-9548",
68+
"https://github.com/FasterXML/jackson-databind/issues/2634",
69+
"https://github.com/advisories/GHSA-p43x-xfjf-5jhr",
70+
"https://lists.apache.org/thread.html/r35d30db00440ef63b791c4b7f7acb036e14d4a23afa2a249cb66c0fd@%3Cissues.zookeeper.apache.org%3E",
71+
"https://lists.apache.org/thread.html/r9464a40d25c3ba1a55622db72f113eb494a889656962d098c70c5bb1@%3Cdev.zookeeper.apache.org%3E",
72+
"https://lists.apache.org/thread.html/r98c9b6e4c9e17792e2cd1ec3e4aa20b61a791939046d3f10888176bb@%3Cissues.zookeeper.apache.org%3E",
73+
"https://lists.apache.org/thread.html/rb6fecb5e96a6d61e175ff49f33f2713798dd05cf03067c169d195596@%3Cissues.zookeeper.apache.org%3E",
74+
"https://lists.apache.org/thread.html/rd5a4457be4623038c3989294429bc063eec433a2e55995d81591e2ca@%3Cissues.zookeeper.apache.org%3E",
75+
"https://lists.apache.org/thread.html/rdd49ab9565bec436a896bc00c4b9fc9dce1598e106c318524fbdfec6@%3Cissues.zookeeper.apache.org%3E",
76+
"https://lists.apache.org/thread.html/rdd4df698d5d8e635144d2994922bf0842e933809eae259521f3b5097@%3Cissues.zookeeper.apache.org%3E",
77+
"https://lists.apache.org/thread.html/rf1bbc0ea4a9f014cf94df9a12a6477d24a27f52741dbc87f2fd52ff2@%3Cissues.geode.apache.org%3E",
78+
"https://lists.debian.org/debian-lts-announce/2020/03/msg00008.html",
79+
"https://medium.com/@cowtowncoder/on-jackson-cves-dont-panic-here-is-what-you-need-to-know-54cd0d6e8062",
80+
"https://nvd.nist.gov/vuln/detail/CVE-2020-9548",
81+
"https://security.netapp.com/advisory/ntap-20200904-0006/",
82+
"https://www.oracle.com/security-alerts/cpujan2021.html",
83+
"https://www.oracle.com/security-alerts/cpujul2020.html",
84+
"https://www.oracle.com/security-alerts/cpuoct2020.html",
85+
"https://www.oracle.com/security-alerts/cpuoct2021.html"
86+
],
87+
"PublishedDate": "2020-03-02T04:15:00Z",
88+
"LastModifiedDate": "2021-12-02T21:23:00Z"
89+
},
90+
{
91+
"VulnerabilityID": "CVE-2021-20190",
92+
"PkgID": "com.fasterxml.jackson.core:jackson-databind:2.9.1",
93+
"PkgName": "com.fasterxml.jackson.core:jackson-databind",
94+
"PkgIdentifier": {
95+
"PURL": "pkg:maven/com.fasterxml.jackson.core/[email protected]",
96+
"UID": "9ccd2eb3e03373ff"
97+
},
98+
"InstalledVersion": "2.9.1",
99+
"FixedVersion": "2.9.10.7",
100+
"Status": "fixed",
101+
"Layer": {},
102+
"SeveritySource": "nvd",
103+
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2021-20190",
104+
"DataSource": {
105+
"ID": "glad",
106+
"Name": "GitLab Advisory Database Community",
107+
"URL": "https://gitlab.com/gitlab-org/advisories-community"
108+
},
109+
"Title": "jackson-databind: mishandles the interaction between serialization gadgets and typing, related to javax.swing",
110+
"Description": "A flaw was found in jackson-databind before 2.9.10.7. FasterXML mishandles the interaction between serialization gadgets and typing. The highest threat from this vulnerability is to data confidentiality and integrity as well as system availability.",
111+
"Severity": "HIGH",
112+
"CweIDs": [
113+
"CWE-502"
114+
],
115+
"VendorSeverity": {
116+
"ghsa": 3,
117+
"nvd": 3,
118+
"redhat": 3
119+
},
120+
"CVSS": {
121+
"nvd": {
122+
"V2Vector": "AV:N/AC:M/Au:N/C:P/I:P/A:C",
123+
"V3Vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
124+
"V2Score": 8.3,
125+
"V3Score": 8.1
126+
},
127+
"redhat": {
128+
"V3Vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
129+
"V3Score": 8.1
130+
}
131+
},
132+
"References": [
133+
"https://access.redhat.com/security/cve/CVE-2021-20190",
134+
"https://bugzilla.redhat.com/show_bug.cgi?id=1916633",
135+
"https://github.com/FasterXML/jackson-databind/commit/7dbf51bf78d157098074a20bd9da39bd48c18e4a",
136+
"https://github.com/FasterXML/jackson-databind/issues/2854",
137+
"https://github.com/advisories/GHSA-5949-rw7g-wx7w",
138+
"https://lists.apache.org/thread.html/r380e9257bacb8551ee6fcf2c59890ae9477b2c78e553fa9ea08e9d9a@%3Ccommits.nifi.apache.org%3E",
139+
"https://lists.debian.org/debian-lts-announce/2021/04/msg00025.html",
140+
"https://nvd.nist.gov/vuln/detail/CVE-2021-20190",
141+
"https://security.netapp.com/advisory/ntap-20210219-0008/"
142+
],
143+
"PublishedDate": "2021-01-19T17:15:00Z",
144+
"LastModifiedDate": "2021-07-20T23:15:00Z"
145+
}
146+
]
147+
}
148+
]
149+
}

pkg/dependency/id.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func ID(ltype types.LangType, name, version string) string {
2525
if !strings.HasPrefix(version, "v") {
2626
version = "v" + version
2727
}
28-
case types.Jar, types.Pom, types.Gradle:
28+
case types.Jar, types.Pom, types.Gradle, types.Sbt:
2929
sep = ":"
3030
}
3131
return name + sep + version

pkg/dependency/id_test.go

+9
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,15 @@ func TestID(t *testing.T) {
4747
},
4848
want: "test:1.0.0",
4949
},
50+
{
51+
name: "sbt",
52+
args: args{
53+
ltype: types.Sbt,
54+
name: "test",
55+
version: "1.0.0",
56+
},
57+
want: "test:1.0.0",
58+
},
5059
{
5160
name: "pip",
5261
args: args{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package lockfile
2+
3+
import (
4+
"io"
5+
"slices"
6+
"sort"
7+
8+
"github.com/liamg/jfather"
9+
"golang.org/x/xerrors"
10+
11+
"github.com/aquasecurity/trivy/pkg/dependency"
12+
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
13+
xio "github.com/aquasecurity/trivy/pkg/x/io"
14+
)
15+
16+
// lockfile format defined at: https://stringbean.github.io/sbt-dependency-lock/file-formats/version-1.html
17+
type sbtLockfile struct {
18+
Version int `json:"lockVersion"`
19+
Dependencies []sbtLockfileDependency `json:"dependencies"`
20+
}
21+
22+
type sbtLockfileDependency struct {
23+
Organization string `json:"org"`
24+
Name string `json:"name"`
25+
Version string `json:"version"`
26+
Configurations []string `json:"configurations"`
27+
StartLine int
28+
EndLine int
29+
}
30+
31+
type Parser struct{}
32+
33+
func NewParser() *Parser {
34+
return &Parser{}
35+
}
36+
37+
func (Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) {
38+
var lockfile sbtLockfile
39+
input, err := io.ReadAll(r)
40+
41+
if err != nil {
42+
return nil, nil, xerrors.Errorf("failed to read sbt lockfile: %w", err)
43+
}
44+
if err := jfather.Unmarshal(input, &lockfile); err != nil {
45+
return nil, nil, xerrors.Errorf("JSON decoding failed: %w", err)
46+
}
47+
48+
var libraries ftypes.Packages
49+
50+
for _, dep := range lockfile.Dependencies {
51+
if slices.ContainsFunc(dep.Configurations, isIncludedConfig) {
52+
name := dep.Organization + ":" + dep.Name
53+
libraries = append(libraries, ftypes.Package{
54+
ID: dependency.ID(ftypes.Sbt, name, dep.Version),
55+
Name: name,
56+
Version: dep.Version,
57+
Locations: []ftypes.Location{
58+
{
59+
StartLine: dep.StartLine,
60+
EndLine: dep.EndLine,
61+
},
62+
},
63+
})
64+
}
65+
}
66+
67+
sort.Sort(libraries)
68+
return libraries, nil, nil
69+
}
70+
71+
// UnmarshalJSONWithMetadata needed to detect start and end lines of deps
72+
func (t *sbtLockfileDependency) UnmarshalJSONWithMetadata(node jfather.Node) error {
73+
if err := node.Decode(&t); err != nil {
74+
return err
75+
}
76+
// Decode func will overwrite line numbers if we save them first
77+
t.StartLine = node.Range().Start.Line
78+
t.EndLine = node.Range().End.Line
79+
return nil
80+
}
81+
82+
func isIncludedConfig(config string) bool {
83+
return config == "compile" || config == "runtime"
84+
}

0 commit comments

Comments
 (0)