mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 16:33:21 +01:00
256 lines
7.0 KiB
Go
256 lines
7.0 KiB
Go
package java
|
|
|
|
import (
|
|
"bufio"
|
|
"github.com/anchore/imgbom/imgbom/pkg"
|
|
"github.com/go-test/deep"
|
|
"github.com/gookit/color"
|
|
"io"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"syscall"
|
|
"testing"
|
|
)
|
|
|
|
func generateJavaBuildFixture(t *testing.T, fixturePath string) {
|
|
if _, err := os.Stat(fixturePath); !os.IsNotExist(err) {
|
|
// fixture already exists...
|
|
return
|
|
}
|
|
|
|
makeTask := strings.TrimPrefix(fixturePath, "test-fixtures/java-builds/")
|
|
t.Logf(color.Bold.Sprintf("Generating Fixture from 'make %s'", makeTask))
|
|
|
|
cwd, err := os.Getwd()
|
|
if err != nil {
|
|
t.Errorf("unable to get cwd: %+v", err)
|
|
}
|
|
|
|
cmd := exec.Command("make", makeTask)
|
|
cmd.Dir = filepath.Join(cwd, "test-fixtures/java-builds/")
|
|
|
|
stderr, err := cmd.StderrPipe()
|
|
if err != nil {
|
|
t.Fatalf("could not get stderr: %+v", err)
|
|
}
|
|
stdout, err := cmd.StdoutPipe()
|
|
if err != nil {
|
|
t.Fatalf("could not get stdout: %+v", err)
|
|
}
|
|
|
|
err = cmd.Start()
|
|
if err != nil {
|
|
t.Fatalf("failed to start cmd: %+v", err)
|
|
}
|
|
|
|
show := func(label string, reader io.ReadCloser) {
|
|
scanner := bufio.NewScanner(reader)
|
|
scanner.Split(bufio.ScanLines)
|
|
for scanner.Scan() {
|
|
t.Logf("%s: %s", label, scanner.Text())
|
|
}
|
|
}
|
|
go show("out", stdout)
|
|
go show("err", stderr)
|
|
|
|
if err := cmd.Wait(); err != nil {
|
|
if exiterr, ok := err.(*exec.ExitError); ok {
|
|
// The program has exited with an exit code != 0
|
|
|
|
// This works on both Unix and Windows. Although package
|
|
// syscall is generally platform dependent, WaitStatus is
|
|
// defined for both Unix and Windows and in both cases has
|
|
// an ExitStatus() method with the same signature.
|
|
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
|
|
if status.ExitStatus() != 0 {
|
|
t.Fatalf("failed to generate fixture: rc=%d", status.ExitStatus())
|
|
}
|
|
}
|
|
} else {
|
|
t.Fatalf("unable to get generate fixture result: %+v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestParseJar(t *testing.T) {
|
|
tests := []struct {
|
|
fixture string
|
|
expected map[string]pkg.Package
|
|
ignoreExtras []string
|
|
}{
|
|
{
|
|
fixture: "test-fixtures/java-builds/packages/example-jenkins-plugin.hpi",
|
|
ignoreExtras: []string{"Plugin-Version"}, // has dynamic date
|
|
expected: map[string]pkg.Package{
|
|
"example-jenkins-plugin": {
|
|
Name: "example-jenkins-plugin",
|
|
Version: "1.0-SNAPSHOT",
|
|
Language: pkg.Java,
|
|
Type: pkg.JenkinsPluginPkg,
|
|
Metadata: pkg.JavaMetadata{
|
|
Manifest: &pkg.JavaManifest{
|
|
ManifestVersion: "1.0",
|
|
SpecTitle: "The Jenkins Plugins Parent POM Project",
|
|
ImplTitle: "example-jenkins-plugin",
|
|
ImplVersion: "1.0-SNAPSHOT",
|
|
Extra: map[string]string{
|
|
"Archiver-Version": "Plexus Archiver",
|
|
"Plugin-License-Url": "https://opensource.org/licenses/MIT",
|
|
"Plugin-License-Name": "MIT License",
|
|
"Created-By": "Apache Maven",
|
|
"Built-By": "?",
|
|
"Build-Jdk": "14.0.1",
|
|
"Jenkins-Version": "2.164.3",
|
|
"Minimum-Java-Version": "1.8",
|
|
"Plugin-Developers": "",
|
|
"Plugin-ScmUrl": "https://github.com/jenkinsci/plugin-pom/example-jenkins-plugin",
|
|
"Extension-Name": "example-jenkins-plugin",
|
|
"Short-Name": "example-jenkins-plugin",
|
|
"Group-Id": "io.jenkins.plugins",
|
|
"Plugin-Dependencies": "structs:1.20",
|
|
//"Plugin-Version": "1.0-SNAPSHOT (private-07/09/2020 13:30-?)",
|
|
"Hudson-Version": "2.164.3",
|
|
"Long-Name": "TODO Plugin",
|
|
},
|
|
},
|
|
PomProperties: &pkg.PomProperties{
|
|
Path: "META-INF/maven/io.jenkins.plugins/example-jenkins-plugin/pom.properties",
|
|
GroupID: "io.jenkins.plugins",
|
|
ArtifactID: "example-jenkins-plugin",
|
|
Version: "1.0-SNAPSHOT",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
fixture: "test-fixtures/java-builds/packages/example-java-app-gradle-0.1.0.jar",
|
|
expected: map[string]pkg.Package{
|
|
"example-java-app-gradle": {
|
|
Name: "example-java-app-gradle",
|
|
Version: "0.1.0",
|
|
Language: pkg.Java,
|
|
Type: pkg.JavaPkg,
|
|
Metadata: pkg.JavaMetadata{
|
|
Manifest: &pkg.JavaManifest{
|
|
ManifestVersion: "1.0",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
fixture: "test-fixtures/java-builds/packages/example-java-app-maven-0.1.0.jar",
|
|
expected: map[string]pkg.Package{
|
|
"example-java-app-maven": {
|
|
Name: "example-java-app-maven",
|
|
Version: "0.1.0",
|
|
Language: pkg.Java,
|
|
Type: pkg.JavaPkg,
|
|
Metadata: pkg.JavaMetadata{
|
|
Manifest: &pkg.JavaManifest{
|
|
ManifestVersion: "1.0",
|
|
Extra: map[string]string{
|
|
"Archiver-Version": "Plexus Archiver",
|
|
"Created-By": "Apache Maven 3.6.3",
|
|
"Built-By": "?",
|
|
"Build-Jdk": "14.0.1",
|
|
"Main-Class": "hello.HelloWorld",
|
|
},
|
|
},
|
|
PomProperties: &pkg.PomProperties{
|
|
Path: "META-INF/maven/org.anchore/example-java-app-maven/pom.properties",
|
|
GroupID: "org.anchore",
|
|
ArtifactID: "example-java-app-maven",
|
|
Version: "0.1.0",
|
|
},
|
|
},
|
|
},
|
|
"joda-time": {
|
|
Name: "joda-time",
|
|
Version: "2.9.2",
|
|
Language: pkg.Java,
|
|
Type: pkg.UnknownPkg,
|
|
Metadata: pkg.JavaMetadata{
|
|
PomProperties: &pkg.PomProperties{
|
|
Path: "META-INF/maven/joda-time/joda-time/pom.properties",
|
|
GroupID: "joda-time",
|
|
ArtifactID: "joda-time",
|
|
Version: "2.9.2",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.fixture, func(t *testing.T) {
|
|
|
|
generateJavaBuildFixture(t, test.fixture)
|
|
|
|
fixture, err := os.Open(test.fixture)
|
|
if err != nil {
|
|
t.Fatalf("failed to open fixture: %+v", err)
|
|
}
|
|
|
|
actual, err := parseJavaArchive(fixture.Name(), fixture)
|
|
if err != nil {
|
|
t.Fatalf("failed to parse java archive: %+v", err)
|
|
}
|
|
|
|
if len(actual) != len(test.expected) {
|
|
for _, a := range actual {
|
|
t.Log(" ", a)
|
|
}
|
|
t.Fatalf("unexpected package count: %d!=%d", len(actual), 1)
|
|
}
|
|
|
|
var parent *pkg.Package
|
|
for _, a := range actual {
|
|
if strings.Contains(a.Name, "example-") {
|
|
parent = &a
|
|
}
|
|
}
|
|
|
|
if parent == nil {
|
|
t.Fatal("could not find the parent pkg")
|
|
}
|
|
|
|
for _, a := range actual {
|
|
e, ok := test.expected[a.Name]
|
|
if !ok {
|
|
t.Errorf("entry not found: %s", a.Name)
|
|
continue
|
|
}
|
|
|
|
if a.Name != parent.Name && a.Metadata.(pkg.JavaMetadata).Parent != nil && a.Metadata.(pkg.JavaMetadata).Parent.Name != parent.Name {
|
|
t.Errorf("mismatched parent: %+v", a.Metadata.(pkg.JavaMetadata).Parent)
|
|
}
|
|
|
|
// we need to compare the other fields without parent attached
|
|
metadata := a.Metadata.(pkg.JavaMetadata)
|
|
metadata.Parent = nil
|
|
|
|
// ignore select fields
|
|
for _, field := range test.ignoreExtras {
|
|
delete(metadata.Manifest.Extra, field)
|
|
}
|
|
|
|
// write censored data back
|
|
a.Metadata = metadata
|
|
|
|
diffs := deep.Equal(a, e)
|
|
if len(diffs) > 0 {
|
|
t.Errorf("diffs found for %q", a.Name)
|
|
for _, d := range diffs {
|
|
t.Errorf("diff: %+v", d)
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|