Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(java): add support for sbt projects using sbt-dependency-lock #6882

Merged
merged 15 commits into from
Jun 19, 2024
2 changes: 2 additions & 0 deletions docs/docs/configuration/reporting.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ The following languages are currently supported:
| PHP | [composer.lock][composer-lock] |
| Java | [pom.xml][pom-xml] |
| | [*gradle.lockfile][gradle-lockfile] |
| | [*.sbt.lock][sbt-lockfile] |
| Dart | [pubspec.lock][pubspec-lock] |

This tree is the reverse of the dependency graph.
Expand Down Expand Up @@ -447,5 +448,6 @@ $ trivy convert --format table --severity CRITICAL result.json
[composer-lock]: ../coverage/language/php.md#composer
[pom-xml]: ../coverage/language/java.md#pomxml
[gradle-lockfile]: ../coverage/language/java.md#gradlelock
[sbt-lockfile]: ../coverage/language/java.md#sbt
[pubspec-lock]: ../coverage/language/dart.md#dart
[cargo-binaries]: ../coverage/language/rust.md#binaries
1 change: 1 addition & 0 deletions docs/docs/coverage/language/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ On the other hand, when the target is a post-build artifact, like a container im
| [Java](java.md) | JAR/WAR/PAR/EAR[^4] | ✅ | ✅ | - | - |
| | pom.xml | - | - | ✅ | ✅ |
| | *gradle.lockfile | - | - | ✅ | ✅ |
| | *.sbt.lock | - | - | ✅ | ✅ |
| [Go](golang.md) | Binaries built by Go | ✅ | ✅ | - | - |
| | go.mod | - | - | ✅ | ✅ |
| [Rust](rust.md) | Cargo.lock | ✅ | ✅ | ✅ | ✅ |
Expand Down
16 changes: 14 additions & 2 deletions docs/docs/coverage/language/java.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Java
Trivy supports three types of Java scanning: `JAR/WAR/PAR/EAR`, `pom.xml` and `*gradle.lockfile` files.
Trivy supports four types of Java scanning: `JAR/WAR/PAR/EAR`, `pom.xml`, `*gradle.lockfile` and `*.sbt.lock` files.

Each artifact supports the following scanners:

Expand All @@ -8,6 +8,7 @@ Each artifact supports the following scanners:
| JAR/WAR/PAR/EAR | ✓ | ✓ | - |
| pom.xml | ✓ | ✓ | ✓ |
| *gradle.lockfile | ✓ | ✓ | ✓ |
| *.sbt.lock | ✓ | ✓ | - |

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

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

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

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


## SBT

`build.sbt.lock` files only contain information about used dependencies. This requires a lockfile generated using the
[sbt-dependency-lock][sbt-dependency-lock] plugin.

!!!note
All necessary files are checked locally. SBT file scanning doesn't require internet access.

[^1]: Uses maven repository to get information about dependencies. Internet access required.
[^2]: It means `*.jar`, `*.war`, `*.par` and `*.ear` file
[^3]: `ArtifactID`, `GroupID` and `Version`
Expand All @@ -106,4 +117,5 @@ Make sure that you have cache[^8] directory to find licenses from `*.pom` depend
[dependency-graph]: ../../configuration/reporting.md#show-origins-of-vulnerable-dependencies
[maven-invoker-plugin]: https://maven.apache.org/plugins/maven-invoker-plugin/usage.html
[maven-central]: https://repo.maven.apache.org/maven2/
[maven-pom-repos]: https://maven.apache.org/settings.html#repositories
[maven-pom-repos]: https://maven.apache.org/settings.html#repositories
[sbt-dependency-lock]: https://stringbean.github.io/sbt-dependency-lock
8 changes: 8 additions & 0 deletions integration/repo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,14 @@ func TestRepository(t *testing.T) {
},
golden: "testdata/gradle.json.golden",
},
{
name: "sbt",
args: args{
scanner: types.VulnerabilityScanner,
input: "testdata/fixtures/repo/sbt",
},
golden: "testdata/sbt.json.golden",
},
{
name: "conan",
args: args{
Expand Down
29 changes: 29 additions & 0 deletions integration/testdata/fixtures/repo/sbt/build.sbt.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"lockVersion" : 1,
"timestamp" : "2024-06-06T11:03:09.964557Z",
"configurations" : [
"compile",
"optional",
"provided",
"runtime",
"test"
],
"dependencies" : [
{
"org" : "com.fasterxml.jackson.core",
"name" : "jackson-databind",
"version" : "2.9.1",
"artifacts" : [
{
"name" : "jackson-databind.jar",
"hash" : "sha1:716da1830a2043f18882fc036ec26eb32cbe5aff"
}
],
"configurations" : [
"compile",
"runtime",
"test"
]
}
]
}
149 changes: 149 additions & 0 deletions integration/testdata/sbt.json.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
{
"SchemaVersion": 2,
"CreatedAt": "2021-08-25T12:20:30.000000005Z",
"ArtifactName": "testdata/fixtures/repo/sbt",
"ArtifactType": "repository",
"Metadata": {
"ImageConfig": {
"architecture": "",
"created": "0001-01-01T00:00:00Z",
"os": "",
"rootfs": {
"type": "",
"diff_ids": null
},
"config": {}
}
},
"Results": [
{
"Target": "build.sbt.lock",
"Class": "lang-pkgs",
"Type": "sbt",
"Vulnerabilities": [
{
"VulnerabilityID": "CVE-2020-9548",
"PkgID": "com.fasterxml.jackson.core:jackson-databind:2.9.1",
"PkgName": "com.fasterxml.jackson.core:jackson-databind",
"PkgIdentifier": {
"PURL": "pkg:maven/com.fasterxml.jackson.core/[email protected]",
"UID": "9ccd2eb3e03373ff"
},
"InstalledVersion": "2.9.1",
"FixedVersion": "2.9.10.4",
"Status": "fixed",
"Layer": {},
"SeveritySource": "ghsa",
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2020-9548",
"DataSource": {
"ID": "ghsa",
"Name": "GitHub Security Advisory Maven",
"URL": "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Amaven"
},
"Title": "jackson-databind: Serialization gadgets in anteros-core",
"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).",
"Severity": "CRITICAL",
"CweIDs": [
"CWE-502"
],
"VendorSeverity": {
"ghsa": 4,
"nvd": 4,
"redhat": 3
},
"CVSS": {
"nvd": {
"V2Vector": "AV:N/AC:M/Au:N/C:P/I:P/A:P",
"V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"V2Score": 6.8,
"V3Score": 9.8
},
"redhat": {
"V3Vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
"V3Score": 8.1
}
},
"References": [
"https://access.redhat.com/security/cve/CVE-2020-9548",
"https://github.com/FasterXML/jackson-databind/issues/2634",
"https://github.com/advisories/GHSA-p43x-xfjf-5jhr",
"https://lists.apache.org/thread.html/r35d30db00440ef63b791c4b7f7acb036e14d4a23afa2a249cb66c0fd@%3Cissues.zookeeper.apache.org%3E",
"https://lists.apache.org/thread.html/r9464a40d25c3ba1a55622db72f113eb494a889656962d098c70c5bb1@%3Cdev.zookeeper.apache.org%3E",
"https://lists.apache.org/thread.html/r98c9b6e4c9e17792e2cd1ec3e4aa20b61a791939046d3f10888176bb@%3Cissues.zookeeper.apache.org%3E",
"https://lists.apache.org/thread.html/rb6fecb5e96a6d61e175ff49f33f2713798dd05cf03067c169d195596@%3Cissues.zookeeper.apache.org%3E",
"https://lists.apache.org/thread.html/rd5a4457be4623038c3989294429bc063eec433a2e55995d81591e2ca@%3Cissues.zookeeper.apache.org%3E",
"https://lists.apache.org/thread.html/rdd49ab9565bec436a896bc00c4b9fc9dce1598e106c318524fbdfec6@%3Cissues.zookeeper.apache.org%3E",
"https://lists.apache.org/thread.html/rdd4df698d5d8e635144d2994922bf0842e933809eae259521f3b5097@%3Cissues.zookeeper.apache.org%3E",
"https://lists.apache.org/thread.html/rf1bbc0ea4a9f014cf94df9a12a6477d24a27f52741dbc87f2fd52ff2@%3Cissues.geode.apache.org%3E",
"https://lists.debian.org/debian-lts-announce/2020/03/msg00008.html",
"https://medium.com/@cowtowncoder/on-jackson-cves-dont-panic-here-is-what-you-need-to-know-54cd0d6e8062",
"https://nvd.nist.gov/vuln/detail/CVE-2020-9548",
"https://security.netapp.com/advisory/ntap-20200904-0006/",
"https://www.oracle.com/security-alerts/cpujan2021.html",
"https://www.oracle.com/security-alerts/cpujul2020.html",
"https://www.oracle.com/security-alerts/cpuoct2020.html",
"https://www.oracle.com/security-alerts/cpuoct2021.html"
],
"PublishedDate": "2020-03-02T04:15:00Z",
"LastModifiedDate": "2021-12-02T21:23:00Z"
},
{
"VulnerabilityID": "CVE-2021-20190",
"PkgID": "com.fasterxml.jackson.core:jackson-databind:2.9.1",
"PkgName": "com.fasterxml.jackson.core:jackson-databind",
"PkgIdentifier": {
"PURL": "pkg:maven/com.fasterxml.jackson.core/[email protected]",
"UID": "9ccd2eb3e03373ff"
},
"InstalledVersion": "2.9.1",
"FixedVersion": "2.9.10.7",
"Status": "fixed",
"Layer": {},
"SeveritySource": "nvd",
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2021-20190",
"DataSource": {
"ID": "glad",
"Name": "GitLab Advisory Database Community",
"URL": "https://gitlab.com/gitlab-org/advisories-community"
},
"Title": "jackson-databind: mishandles the interaction between serialization gadgets and typing, related to javax.swing",
"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.",
"Severity": "HIGH",
"CweIDs": [
"CWE-502"
],
"VendorSeverity": {
"ghsa": 3,
"nvd": 3,
"redhat": 3
},
"CVSS": {
"nvd": {
"V2Vector": "AV:N/AC:M/Au:N/C:P/I:P/A:C",
"V3Vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
"V2Score": 8.3,
"V3Score": 8.1
},
"redhat": {
"V3Vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
"V3Score": 8.1
}
},
"References": [
"https://access.redhat.com/security/cve/CVE-2021-20190",
"https://bugzilla.redhat.com/show_bug.cgi?id=1916633",
"https://github.com/FasterXML/jackson-databind/commit/7dbf51bf78d157098074a20bd9da39bd48c18e4a",
"https://github.com/FasterXML/jackson-databind/issues/2854",
"https://github.com/advisories/GHSA-5949-rw7g-wx7w",
"https://lists.apache.org/thread.html/r380e9257bacb8551ee6fcf2c59890ae9477b2c78e553fa9ea08e9d9a@%3Ccommits.nifi.apache.org%3E",
"https://lists.debian.org/debian-lts-announce/2021/04/msg00025.html",
"https://nvd.nist.gov/vuln/detail/CVE-2021-20190",
"https://security.netapp.com/advisory/ntap-20210219-0008/"
],
"PublishedDate": "2021-01-19T17:15:00Z",
"LastModifiedDate": "2021-07-20T23:15:00Z"
}
]
}
]
}
2 changes: 1 addition & 1 deletion pkg/dependency/id.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func ID(ltype types.LangType, name, version string) string {
if !strings.HasPrefix(version, "v") {
version = "v" + version
}
case types.Jar, types.Pom, types.Gradle:
case types.Jar, types.Pom, types.Gradle, types.Sbt:
sep = ":"
}
return name + sep + version
Expand Down
9 changes: 9 additions & 0 deletions pkg/dependency/id_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ func TestID(t *testing.T) {
},
want: "test:1.0.0",
},
{
name: "sbt",
args: args{
ltype: types.Sbt,
name: "test",
version: "1.0.0",
},
want: "test:1.0.0",
},
{
name: "pip",
args: args{
Expand Down
84 changes: 84 additions & 0 deletions pkg/dependency/parser/sbt/lockfile/parse.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package lockfile

import (
"io"
"slices"
"sort"

"github.com/liamg/jfather"
"golang.org/x/xerrors"

"github.com/aquasecurity/trivy/pkg/dependency"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
xio "github.com/aquasecurity/trivy/pkg/x/io"
)

// lockfile format defined at: https://stringbean.github.io/sbt-dependency-lock/file-formats/version-1.html
type sbtLockfile struct {
Version int `json:"lockVersion"`
Dependencies []sbtLockfileDependency `json:"dependencies"`
}

type sbtLockfileDependency struct {
Organization string `json:"org"`
Name string `json:"name"`
Version string `json:"version"`
Configurations []string `json:"configurations"`
StartLine int
EndLine int
}

type Parser struct{}

func NewParser() *Parser {
return &Parser{}
}

func (Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) {
var lockfile sbtLockfile
input, err := io.ReadAll(r)

if err != nil {
return nil, nil, xerrors.Errorf("failed to read sbt lockfile: %w", err)
}
if err := jfather.Unmarshal(input, &lockfile); err != nil {
return nil, nil, xerrors.Errorf("JSON decoding failed: %w", err)
}

var libraries ftypes.Packages

for _, dep := range lockfile.Dependencies {
if slices.ContainsFunc(dep.Configurations, isIncludedConfig) {
name := dep.Organization + ":" + dep.Name
libraries = append(libraries, ftypes.Package{
ID: dependency.ID(ftypes.Sbt, name, dep.Version),
Name: name,
Version: dep.Version,
Locations: []ftypes.Location{
{
StartLine: dep.StartLine,
EndLine: dep.EndLine,
},
},
})
}
}

sort.Sort(libraries)
return libraries, nil, nil
stringbean marked this conversation as resolved.
Show resolved Hide resolved
}

// UnmarshalJSONWithMetadata needed to detect start and end lines of deps
func (t *sbtLockfileDependency) UnmarshalJSONWithMetadata(node jfather.Node) error {
if err := node.Decode(&t); err != nil {
return err
}
// Decode func will overwrite line numbers if we save them first
t.StartLine = node.Range().Start.Line
t.EndLine = node.Range().End.Line
return nil
}

func isIncludedConfig(config string) bool {
return config == "compile" || config == "runtime"
}
Loading