mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 16:33:21 +01:00
feat: gradle lockfile support (#1719)
Signed-off-by: Henry Sachs <Henry.Sachs@deutschebahn.com>
This commit is contained in:
parent
da44db92e9
commit
0fed17f1c8
@ -73,6 +73,7 @@ func DirectoryCatalogers(cfg Config) []pkg.Cataloger {
|
|||||||
java.NewJavaCataloger(cfg.Java()),
|
java.NewJavaCataloger(cfg.Java()),
|
||||||
java.NewJavaPomCataloger(),
|
java.NewJavaPomCataloger(),
|
||||||
java.NewNativeImageCataloger(),
|
java.NewNativeImageCataloger(),
|
||||||
|
java.NewJavaGradleLockfileCataloger(),
|
||||||
apkdb.NewApkdbCataloger(),
|
apkdb.NewApkdbCataloger(),
|
||||||
golang.NewGoModuleBinaryCataloger(cfg.Go()),
|
golang.NewGoModuleBinaryCataloger(cfg.Go()),
|
||||||
golang.NewGoModFileCataloger(cfg.Go()),
|
golang.NewGoModFileCataloger(cfg.Go()),
|
||||||
@ -107,6 +108,7 @@ func AllCatalogers(cfg Config) []pkg.Cataloger {
|
|||||||
java.NewJavaCataloger(cfg.Java()),
|
java.NewJavaCataloger(cfg.Java()),
|
||||||
java.NewJavaPomCataloger(),
|
java.NewJavaPomCataloger(),
|
||||||
java.NewNativeImageCataloger(),
|
java.NewNativeImageCataloger(),
|
||||||
|
java.NewJavaGradleLockfileCataloger(),
|
||||||
apkdb.NewApkdbCataloger(),
|
apkdb.NewApkdbCataloger(),
|
||||||
golang.NewGoModuleBinaryCataloger(cfg.Go()),
|
golang.NewGoModuleBinaryCataloger(cfg.Go()),
|
||||||
golang.NewGoModFileCataloger(cfg.Go()),
|
golang.NewGoModFileCataloger(cfg.Go()),
|
||||||
|
|||||||
@ -159,10 +159,39 @@ func TestParseJar(t *testing.T) {
|
|||||||
Manifest: &pkg.JavaManifest{
|
Manifest: &pkg.JavaManifest{
|
||||||
Main: map[string]string{
|
Main: map[string]string{
|
||||||
"Manifest-Version": "1.0",
|
"Manifest-Version": "1.0",
|
||||||
|
"Main-Class": "hello.HelloWorld",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"joda-time": {
|
||||||
|
Name: "joda-time",
|
||||||
|
Version: "2.2",
|
||||||
|
PURL: "pkg:maven/joda-time/joda-time@2.2",
|
||||||
|
Language: pkg.Java,
|
||||||
|
Type: pkg.JavaPkg,
|
||||||
|
MetadataType: pkg.JavaMetadataType,
|
||||||
|
Metadata: pkg.JavaMetadata{
|
||||||
|
// ensure that nested packages with different names than that of the parent are appended as
|
||||||
|
// a suffix on the virtual path
|
||||||
|
VirtualPath: "test-fixtures/java-builds/packages/example-java-app-gradle-0.1.0.jar:joda-time",
|
||||||
|
PomProperties: &pkg.PomProperties{
|
||||||
|
Path: "META-INF/maven/joda-time/joda-time/pom.properties",
|
||||||
|
GroupID: "joda-time",
|
||||||
|
ArtifactID: "joda-time",
|
||||||
|
Version: "2.2",
|
||||||
|
},
|
||||||
|
PomProject: &pkg.PomProject{
|
||||||
|
Path: "META-INF/maven/joda-time/joda-time/pom.xml",
|
||||||
|
GroupID: "joda-time",
|
||||||
|
ArtifactID: "joda-time",
|
||||||
|
Version: "2.2",
|
||||||
|
Name: "Joda time",
|
||||||
|
Description: "Date and time library to replace JDK date handling",
|
||||||
|
URL: "http://joda-time.sourceforge.net",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -31,3 +31,11 @@ func NewJavaPomCataloger() *generic.Cataloger {
|
|||||||
return generic.NewCataloger("java-pom-cataloger").
|
return generic.NewCataloger("java-pom-cataloger").
|
||||||
WithParserByGlobs(parserPomXML, "**/pom.xml")
|
WithParserByGlobs(parserPomXML, "**/pom.xml")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewJavaGradleLockfileCataloger returns a cataloger capable of parsing
|
||||||
|
// dependencies from a gradle.lockfile file.
|
||||||
|
// older versions of lockfiles aren't supported yet
|
||||||
|
func NewJavaGradleLockfileCataloger() *generic.Cataloger {
|
||||||
|
return generic.NewCataloger("java-gradle-lockfile-cataloger").
|
||||||
|
WithParserByGlobs(parseGradleLockfile, gradleLockfileGlob)
|
||||||
|
}
|
||||||
|
|||||||
63
syft/pkg/cataloger/java/parse_gradle_lockfile.go
Normal file
63
syft/pkg/cataloger/java/parse_gradle_lockfile.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package java
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||||
|
"github.com/anchore/syft/syft/source"
|
||||||
|
)
|
||||||
|
|
||||||
|
const gradleLockfileGlob = "**/gradle.lockfile*"
|
||||||
|
|
||||||
|
// Dependency represents a single dependency in the gradle.lockfile file
|
||||||
|
type LockfileDependency struct {
|
||||||
|
Group string
|
||||||
|
Name string
|
||||||
|
Version string
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseGradleLockfile(_ source.FileResolver, _ *generic.Environment, reader source.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||||
|
var pkgs []pkg.Package
|
||||||
|
|
||||||
|
// Create a new scanner to read the file
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
// Create slices to hold the dependencies and plugins
|
||||||
|
dependencies := []LockfileDependency{}
|
||||||
|
|
||||||
|
// Loop over all lines in the file
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
|
||||||
|
// Trim leading and trailing whitespace from the line
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
|
||||||
|
groupNameVersion := line
|
||||||
|
groupNameVersion = strings.Split(groupNameVersion, "=")[0]
|
||||||
|
parts := strings.Split(groupNameVersion, ":")
|
||||||
|
|
||||||
|
// we have a version directly specified
|
||||||
|
if len(parts) == 3 {
|
||||||
|
// Create a new Dependency struct and add it to the dependencies slice
|
||||||
|
dep := LockfileDependency{Group: parts[0], Name: parts[1], Version: parts[2]}
|
||||||
|
dependencies = append(dependencies, dep)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// map the dependencies
|
||||||
|
for _, dep := range dependencies {
|
||||||
|
mappedPkg := pkg.Package{
|
||||||
|
Name: dep.Name,
|
||||||
|
Version: dep.Version,
|
||||||
|
Locations: source.NewLocationSet(reader.Location),
|
||||||
|
Language: pkg.Java,
|
||||||
|
Type: pkg.JavaPkg,
|
||||||
|
MetadataType: pkg.JavaMetadataType,
|
||||||
|
}
|
||||||
|
pkgs = append(pkgs, mappedPkg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkgs, nil, nil
|
||||||
|
}
|
||||||
52
syft/pkg/cataloger/java/parse_gradle_lockfile_test.go
Normal file
52
syft/pkg/cataloger/java/parse_gradle_lockfile_test.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package java
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
|
||||||
|
"github.com/anchore/syft/syft/source"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_parserGradleLockfile(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
input string
|
||||||
|
expected []pkg.Package
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
input: "test-fixtures/gradle/gradle.lockfile",
|
||||||
|
expected: []pkg.Package{
|
||||||
|
{
|
||||||
|
Name: "hamcrest-core",
|
||||||
|
Version: "1.3",
|
||||||
|
Language: pkg.Java,
|
||||||
|
Type: pkg.JavaPkg,
|
||||||
|
MetadataType: pkg.JavaMetadataType,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "joda-time",
|
||||||
|
Version: "2.2",
|
||||||
|
Language: pkg.Java,
|
||||||
|
Type: pkg.JavaPkg,
|
||||||
|
MetadataType: pkg.JavaMetadataType,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "junit",
|
||||||
|
Version: "4.12",
|
||||||
|
Language: pkg.Java,
|
||||||
|
Type: pkg.JavaPkg,
|
||||||
|
MetadataType: pkg.JavaMetadataType,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.input, func(t *testing.T) {
|
||||||
|
for i := range test.expected {
|
||||||
|
test.expected[i].Locations.Add(source.NewLocation(test.input))
|
||||||
|
}
|
||||||
|
pkgtest.TestFileParser(t, test.input, parseGradleLockfile, test.expected, nil)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
1
syft/pkg/cataloger/java/test-fixtures/gradle/.gitignore
vendored
Normal file
1
syft/pkg/cataloger/java/test-fixtures/gradle/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
.gradle
|
||||||
58
syft/pkg/cataloger/java/test-fixtures/gradle/build.gradle
Normal file
58
syft/pkg/cataloger/java/test-fixtures/gradle/build.gradle
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
plugins {
|
||||||
|
id 'java'
|
||||||
|
id 'eclipse'
|
||||||
|
id 'application'
|
||||||
|
}
|
||||||
|
|
||||||
|
mainClassName = 'hello.HelloWorld'
|
||||||
|
|
||||||
|
dependencyLocking {
|
||||||
|
lockAllConfigurations()
|
||||||
|
}
|
||||||
|
// tag::repositories[]
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
// end::repositories[]
|
||||||
|
|
||||||
|
// tag::dependencies[]
|
||||||
|
sourceCompatibility = 1.8
|
||||||
|
targetCompatibility = 1.8
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation "joda-time:joda-time:2.2"
|
||||||
|
testImplementation "junit:junit:4.12"
|
||||||
|
}
|
||||||
|
// end::dependencies[]
|
||||||
|
|
||||||
|
// tag::jar[]
|
||||||
|
jar {
|
||||||
|
archivesBaseName = 'example-java-app-gradle'
|
||||||
|
version = '0.1.0'
|
||||||
|
manifest {
|
||||||
|
attributes(
|
||||||
|
'Main-Class': 'hello.HelloWorld'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
from {
|
||||||
|
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// end::jar[]
|
||||||
|
|
||||||
|
// tag::wrapper[]
|
||||||
|
// end::wrapper[]
|
||||||
|
|
||||||
|
// to invoke: gradle resolveAndLockAll --write-locks
|
||||||
|
tasks.register('resolveAndLockAll') {
|
||||||
|
notCompatibleWithConfigurationCache("Filters configurations at execution time")
|
||||||
|
doFirst {
|
||||||
|
assert gradle.startParameter.writeDependencyLocks
|
||||||
|
}
|
||||||
|
doLast {
|
||||||
|
configurations.findAll {
|
||||||
|
// Add any custom filtering on the configurations to be resolved
|
||||||
|
it.canBeResolved
|
||||||
|
}.each { it.resolve() }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
# This is a Gradle generated file for dependency locking.
|
||||||
|
# Manual edits can break the build and are not advised.
|
||||||
|
# This file is expected to be part of source control.
|
||||||
|
joda-time:joda-time:2.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||||
|
junit:junit:4.12=testCompileClasspath,testRuntimeClasspath
|
||||||
|
org.hamcrest:hamcrest-core:1.3=testCompileClasspath,testRuntimeClasspath
|
||||||
|
empty=annotationProcessor,testAnnotationProcessor
|
||||||
@ -4,7 +4,7 @@ set -uxe
|
|||||||
# note: this can be easily done in a 1-liner, however circle CI does NOT allow volume mounts from the host in docker executors (since they are on remote hosts, where the host files are inaccessible)
|
# note: this can be easily done in a 1-liner, however circle CI does NOT allow volume mounts from the host in docker executors (since they are on remote hosts, where the host files are inaccessible)
|
||||||
|
|
||||||
PKGSDIR=$1
|
PKGSDIR=$1
|
||||||
CTRID=$(docker create -u "$(id -u):$(id -g)" -v /example-java-app -w /example-java-app gradle:6.8.3-jdk gradle build)
|
CTRID=$(docker create -u "$(id -u):$(id -g)" -v /example-java-app -w /example-java-app gradle:8.0.2-jdk gradle build)
|
||||||
|
|
||||||
function cleanup() {
|
function cleanup() {
|
||||||
docker rm "${CTRID}"
|
docker rm "${CTRID}"
|
||||||
|
|||||||
@ -1,31 +1,58 @@
|
|||||||
apply plugin: 'java'
|
plugins {
|
||||||
apply plugin: 'eclipse'
|
id 'java'
|
||||||
apply plugin: 'application'
|
id 'eclipse'
|
||||||
|
id 'application'
|
||||||
|
}
|
||||||
|
|
||||||
mainClassName = 'hello.HelloWorld'
|
mainClassName = 'hello.HelloWorld'
|
||||||
|
|
||||||
|
dependencyLocking {
|
||||||
|
lockAllConfigurations()
|
||||||
|
}
|
||||||
// tag::repositories[]
|
// tag::repositories[]
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
// end::repositories[]
|
// end::repositories[]
|
||||||
|
|
||||||
// tag::jar[]
|
|
||||||
jar {
|
|
||||||
baseName = 'example-java-app-gradle'
|
|
||||||
version = '0.1.0'
|
|
||||||
}
|
|
||||||
// end::jar[]
|
|
||||||
|
|
||||||
// tag::dependencies[]
|
// tag::dependencies[]
|
||||||
sourceCompatibility = 1.8
|
sourceCompatibility = 1.8
|
||||||
targetCompatibility = 1.8
|
targetCompatibility = 1.8
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile "joda-time:joda-time:2.2"
|
implementation "joda-time:joda-time:2.2"
|
||||||
testCompile "junit:junit:4.12"
|
testImplementation "junit:junit:4.12"
|
||||||
}
|
}
|
||||||
// end::dependencies[]
|
// end::dependencies[]
|
||||||
|
|
||||||
|
// tag::jar[]
|
||||||
|
jar {
|
||||||
|
archivesBaseName = 'example-java-app-gradle'
|
||||||
|
version = '0.1.0'
|
||||||
|
manifest {
|
||||||
|
attributes(
|
||||||
|
'Main-Class': 'hello.HelloWorld'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
from {
|
||||||
|
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// end::jar[]
|
||||||
|
|
||||||
// tag::wrapper[]
|
// tag::wrapper[]
|
||||||
// end::wrapper[]
|
// end::wrapper[]
|
||||||
|
|
||||||
|
// to invoke: gradle resolveAndLockAll --write-locks
|
||||||
|
tasks.register('resolveAndLockAll') {
|
||||||
|
notCompatibleWithConfigurationCache("Filters configurations at execution time")
|
||||||
|
doFirst {
|
||||||
|
assert gradle.startParameter.writeDependencyLocks
|
||||||
|
}
|
||||||
|
doLast {
|
||||||
|
configurations.findAll {
|
||||||
|
// Add any custom filtering on the configurations to be resolved
|
||||||
|
it.canBeResolved
|
||||||
|
}.each { it.resolve() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -0,0 +1,7 @@
|
|||||||
|
# This is a Gradle generated file for dependency locking.
|
||||||
|
# Manual edits can break the build and are not advised.
|
||||||
|
# This file is expected to be part of source control.
|
||||||
|
joda-time:joda-time:2.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||||
|
junit:junit:4.12=testCompileClasspath,testRuntimeClasspath
|
||||||
|
org.hamcrest:hamcrest-core:1.3=testCompileClasspath,testRuntimeClasspath
|
||||||
|
empty=annotationProcessor,testAnnotationProcessor
|
||||||
Loading…
x
Reference in New Issue
Block a user