github.com/google/osv-scalibr@v0.4.1/enricher/reachability/java/java_test.go (about)

     1  // Copyright 2025 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package java_test
    16  
    17  import (
    18  	"fmt"
    19  	"net/http"
    20  	"net/http/httptest"
    21  	"path/filepath"
    22  	"strings"
    23  	"testing"
    24  
    25  	"github.com/google/osv-scalibr/enricher"
    26  	"github.com/google/osv-scalibr/enricher/reachability/java"
    27  	"github.com/google/osv-scalibr/extractor"
    28  	"github.com/google/osv-scalibr/extractor/filesystem/language/java/archive"
    29  	archivemeta "github.com/google/osv-scalibr/extractor/filesystem/language/java/archive/metadata"
    30  	scalibrfs "github.com/google/osv-scalibr/fs"
    31  	"github.com/google/osv-scalibr/inventory"
    32  	"github.com/google/osv-scalibr/inventory/vex"
    33  	"github.com/google/osv-scalibr/purl"
    34  )
    35  
    36  const (
    37  	testJar               = "javareach-test.jar"
    38  	reachableJar          = "reachable-dep-test.jar"
    39  	unreachableJar        = "unreachable-dep-test.jar"
    40  	reachableGroupID      = "mock.reachable"
    41  	reachableArtifactID   = "foo"
    42  	unreachableGroupID    = "mock.unreachable"
    43  	unreachableArtifactID = "bar"
    44  	version               = "1.0.0"
    45  )
    46  
    47  func TestScan(t *testing.T) {
    48  	jar := filepath.Join("testdata", reachableJar)
    49  
    50  	mockClient := mockClient(t)
    51  	enr := java.NewEnricher(mockClient)
    52  
    53  	pkgs := setupPackages([]string{testJar})
    54  	input := enricher.ScanInput{
    55  		ScanRoot: &scalibrfs.ScanRoot{
    56  			Path: jar,
    57  			FS:   scalibrfs.DirFS("."),
    58  		},
    59  	}
    60  	inv := inventory.Inventory{
    61  		Packages: pkgs,
    62  	}
    63  	err := enr.Enrich(t.Context(), &input, &inv)
    64  	if err != nil {
    65  		t.Fatalf("Javareach enrich failed: %s", err)
    66  	}
    67  
    68  	for _, pkg := range inv.Packages {
    69  		if pkg.Metadata.(*archivemeta.Metadata).ArtifactID == reachableArtifactID {
    70  			for _, signal := range pkg.ExploitabilitySignals {
    71  				if signal.Justification == vex.VulnerableCodeNotInExecutePath {
    72  					t.Fatalf("Javareach enrich failed, expected %s to be reachable, but marked as unreachable", pkg.Name)
    73  				}
    74  			}
    75  		}
    76  		if pkg.Metadata.(*archivemeta.Metadata).ArtifactID == unreachableArtifactID {
    77  			hasUnreachableSignal := false
    78  			for _, signal := range pkg.ExploitabilitySignals {
    79  				if signal.Justification == vex.VulnerableCodeNotInExecutePath {
    80  					hasUnreachableSignal = true
    81  				}
    82  			}
    83  			if !hasUnreachableSignal {
    84  				t.Fatalf("Javareach enrich failed, expected %s to be unreachable, but marked as reachable", pkg.Name)
    85  			}
    86  		}
    87  	}
    88  }
    89  
    90  func mockClient(t *testing.T) *http.Client {
    91  	t.Helper()
    92  	// mock a server to act as Maven Central to avoid network requests.
    93  	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    94  		requestPath := r.URL.Path
    95  		if strings.Contains(requestPath, unreachableArtifactID) {
    96  			http.ServeFile(w, r, filepath.Join("testdata", unreachableJar))
    97  		} else if strings.Contains(requestPath, reachableArtifactID) {
    98  			http.ServeFile(w, r, filepath.Join("testdata", reachableJar))
    99  		}
   100  	}))
   101  
   102  	originalURL := java.MavenBaseURL
   103  	java.MavenBaseURL = server.URL
   104  
   105  	t.Cleanup(func() {
   106  		java.MavenBaseURL = originalURL
   107  		server.Close()
   108  	})
   109  
   110  	return server.Client()
   111  }
   112  
   113  func setupPackages(names []string) []*extractor.Package {
   114  	pkgs := []*extractor.Package{}
   115  	var reachablePkgName = fmt.Sprintf("%s:%s", reachableGroupID, reachableArtifactID)
   116  	var unreachablePkgName = fmt.Sprintf("%s:%s", unreachableGroupID, unreachableArtifactID)
   117  
   118  	for _, n := range names {
   119  		reachablePkg := &extractor.Package{
   120  			Name:      reachablePkgName,
   121  			Version:   version,
   122  			PURLType:  purl.TypeMaven,
   123  			Metadata:  &archivemeta.Metadata{ArtifactID: reachableArtifactID, GroupID: reachableGroupID},
   124  			Locations: []string{filepath.Join("testdata", n)},
   125  			Plugins:   []string{archive.Name},
   126  		}
   127  
   128  		unreachablePkg := &extractor.Package{
   129  			Name:      unreachablePkgName,
   130  			Version:   version,
   131  			PURLType:  purl.TypeMaven,
   132  			Metadata:  &archivemeta.Metadata{ArtifactID: unreachableArtifactID, GroupID: unreachableGroupID},
   133  			Locations: []string{filepath.Join("testdata", n)},
   134  			Plugins:   []string{archive.Name},
   135  		}
   136  
   137  		pkgs = append(pkgs, reachablePkg, unreachablePkg)
   138  	}
   139  
   140  	return pkgs
   141  }