Skip to content

Commit

Permalink
move to internal
Browse files Browse the repository at this point in the history
  • Loading branch information
cuixq committed May 21, 2024
1 parent caebb9a commit 82963d0
Show file tree
Hide file tree
Showing 13 changed files with 651 additions and 386 deletions.
7 changes: 7 additions & 0 deletions internal/manifest/fixtures/maven/empty.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<project>
<modelVersion>4.0.0</modelVersion>

<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</project>
40 changes: 40 additions & 0 deletions internal/manifest/fixtures/maven/interpolation.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>io.library</groupId>
<artifactId>my-library</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<properties>
<mypackageVersion>1.0.0</mypackageVersion>
<my.package.version>2.3.4</my.package.version>
<version-range>[9.4.35.v20201120,9.5)</version-range>
</properties>

<dependencies>
<dependency>
<groupId>org.mine</groupId>
<artifactId>mypackage</artifactId>
<version>${mypackageVersion}</version>
</dependency>

<dependency>
<groupId>org.mine</groupId>
<artifactId>my.package</artifactId>
<version>${my.package.version}</version>
</dependency>
</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.mine</groupId>
<artifactId>ranged-package</artifactId>
<version>${version-range}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
13 changes: 13 additions & 0 deletions internal/manifest/fixtures/maven/invalid-syntax.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<project>
<properties>
<${Id}.version>${project.version}</${Id}.version>
</properties>

<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.42.Final</version>
</dependency>
</dependencies>
</project>
1 change: 1 addition & 0 deletions internal/manifest/fixtures/maven/not-pom.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
this is not a pom.xml file!
13 changes: 13 additions & 0 deletions internal/manifest/fixtures/maven/one-package.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<project>
<properties>
<mavenVersion>3.0</mavenVersion>
</properties>

<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</project>
18 changes: 18 additions & 0 deletions internal/manifest/fixtures/maven/two-packages.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<project>
<properties>
<mavenVersion>3.0</mavenVersion>
</properties>

<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.42.Final</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
</dependencies>
</project>
33 changes: 33 additions & 0 deletions internal/manifest/fixtures/maven/with-dependency-management.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<project>
<properties>
<mavenVersion>3.0</mavenVersion>
</properties>

<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.9</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.42.Final</version>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>3.0.2</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
10 changes: 10 additions & 0 deletions internal/manifest/fixtures/maven/with-scope.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<project>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
105 changes: 105 additions & 0 deletions internal/manifest/helpers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package manifest_test

import (
"errors"
"fmt"
"reflect"
"strings"
"testing"

"github.com/google/osv-scanner/internal/output"
"github.com/google/osv-scanner/pkg/lockfile"
)

func expectErrContaining(t *testing.T, err error, str string) {
t.Helper()

if err == nil {
t.Errorf("Expected to get error, but did not")
}

if !strings.Contains(err.Error(), str) {
t.Errorf("Expected to get \"%s\" error, but got \"%v\"", str, err)
}
}

func expectErrIs(t *testing.T, err error, expected error) {
t.Helper()

if err == nil {
t.Errorf("Expected to get error, but did not")
}

if !errors.Is(err, expected) {
t.Errorf("Expected to get \"%v\" error but got \"%v\" instead", expected, err)
}
}

func packageToString(pkg lockfile.PackageDetails) string {
commit := pkg.Commit

if commit == "" {
commit = "<no commit>"
}

groups := strings.Join(pkg.DepGroups, ", ")

if groups == "" {
groups = "<no groups>"
}

return fmt.Sprintf("%s@%s (%s, %s, %s)", pkg.Name, pkg.Version, pkg.Ecosystem, commit, groups)
}

func hasPackage(t *testing.T, packages []lockfile.PackageDetails, pkg lockfile.PackageDetails) bool {
t.Helper()

for _, details := range packages {
if reflect.DeepEqual(details, pkg) {
return true
}
}

return false
}

func findMissingPackages(t *testing.T, actualPackages []lockfile.PackageDetails, expectedPackages []lockfile.PackageDetails) []lockfile.PackageDetails {
t.Helper()
var missingPackages []lockfile.PackageDetails

for _, pkg := range actualPackages {
if !hasPackage(t, expectedPackages, pkg) {
missingPackages = append(missingPackages, pkg)
}
}

return missingPackages
}

func expectPackages(t *testing.T, actualPackages []lockfile.PackageDetails, expectedPackages []lockfile.PackageDetails) {
t.Helper()

if len(expectedPackages) != len(actualPackages) {
t.Errorf(
"Expected to get %d %s, but got %d",
len(expectedPackages),
output.Form(len(expectedPackages), "package", "packages"),
len(actualPackages),
)
}

missingActualPackages := findMissingPackages(t, actualPackages, expectedPackages)
missingExpectedPackages := findMissingPackages(t, expectedPackages, actualPackages)

if len(missingActualPackages) != 0 {
for _, unexpectedPackage := range missingActualPackages {
t.Errorf("Did not expect %s", packageToString(unexpectedPackage))
}
}

if len(missingExpectedPackages) != 0 {
for _, unexpectedPackage := range missingExpectedPackages {
t.Errorf("Did not find %s", packageToString(unexpectedPackage))
}
}
}
118 changes: 118 additions & 0 deletions internal/manifest/maven.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package manifest

import (
"context"
"encoding/xml"
"fmt"
"path/filepath"

depsdevpb "deps.dev/api/v3"
"deps.dev/util/maven"
"deps.dev/util/semver"
"github.com/google/osv-scanner/pkg/lockfile"
"golang.org/x/exp/maps"
)

type MavenResolverExtractor struct {
Client depsdevpb.InsightsClient
}

func (e MavenResolverExtractor) ShouldExtract(path string) bool {
return filepath.Base(path) == "pom.xml"
}

func (e MavenResolverExtractor) Extract(f lockfile.DepFile) ([]lockfile.PackageDetails, error) {
ctx := context.Background()

var project maven.Project
if err := xml.NewDecoder(f).Decode(&project); err != nil {
return []lockfile.PackageDetails{}, fmt.Errorf("could not extract from %s: %w", f.Path(), err)
}
if err := project.Interpolate(); err != nil {
return []lockfile.PackageDetails{}, fmt.Errorf("could not interpolate Maven project %s: %w", project.ProjectKey.Name(), err)
}

details := map[string]lockfile.PackageDetails{}

for _, dep := range project.Dependencies {
name := dep.Name()
v, err := e.resolveVersion(ctx, dep)
if err != nil {
return []lockfile.PackageDetails{}, err
}
pkgDetails := lockfile.PackageDetails{
Name: name,
Version: v,
Ecosystem: lockfile.MavenEcosystem,
CompareAs: lockfile.MavenEcosystem,
}
if dep.Scope != "" {
pkgDetails.DepGroups = append(pkgDetails.DepGroups, string(dep.Scope))
}
details[name] = pkgDetails
}

// managed dependencies take precedent over standard dependencies
for _, dep := range project.DependencyManagement.Dependencies {
name := dep.Name()
v, err := e.resolveVersion(ctx, dep)
if err != nil {
return []lockfile.PackageDetails{}, err
}
pkgDetails := lockfile.PackageDetails{
Name: name,
Version: v,
Ecosystem: lockfile.MavenEcosystem,
CompareAs: lockfile.MavenEcosystem,
}
if dep.Scope != "" {
pkgDetails.DepGroups = append(pkgDetails.DepGroups, string(dep.Scope))
}
details[name] = pkgDetails
}

return maps.Values(details), nil
}

func (e MavenResolverExtractor) resolveVersion(ctx context.Context, dep maven.Dependency) (string, error) {
constraint, err := semver.Maven.ParseConstraint(string(dep.Version))
if err != nil {
return "", fmt.Errorf("parsing Maven constraint %s: %w", dep.Version, err)
}
if constraint.IsSimple() {
// Return the constraint if it is a simple version string.
return constraint.String(), nil
}

// Otherwise return the greatest version matching the constraint.
// TODO: invoke Maven resolver to decide the exact version.
resp, err := e.Client.GetPackage(ctx, &depsdevpb.GetPackageRequest{
PackageKey: &depsdevpb.PackageKey{
System: depsdevpb.System_MAVEN,
Name: dep.Name(),
},
})
if err != nil {
return "", fmt.Errorf("requesting versions of Maven package %s: %w", dep.Name(), err)
}

var result *semver.Version
for _, ver := range resp.GetVersions() {
v, _ := semver.Maven.Parse(ver.GetVersionKey().GetVersion())
if constraint.MatchVersion(v) && result.Compare(v) < 0 {
result = v
}
}

return result.String(), nil
}

func ParseMavenWithResolver(depsdev depsdevpb.InsightsClient, pathToLockfile string) ([]lockfile.PackageDetails, error) {
f, err := lockfile.OpenLocalDepFile(pathToLockfile)
if err != nil {
return []lockfile.PackageDetails{}, err
}
defer f.Close()

return MavenResolverExtractor{Client: depsdev}.Extract(f)
}
Loading

0 comments on commit 82963d0

Please sign in to comment.