github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/syft/format/internal/testutil/image_input.go (about)

     1  package testutil
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/require"
     9  
    10  	"github.com/anchore/stereoscope/pkg/filetree"
    11  	"github.com/anchore/stereoscope/pkg/image"
    12  	"github.com/anchore/stereoscope/pkg/imagetest"
    13  	"github.com/anchore/syft/syft/cpe"
    14  	"github.com/anchore/syft/syft/file"
    15  	"github.com/anchore/syft/syft/linux"
    16  	"github.com/anchore/syft/syft/pkg"
    17  	"github.com/anchore/syft/syft/sbom"
    18  	"github.com/anchore/syft/syft/source/stereoscopesource"
    19  )
    20  
    21  func ImageInput(t testing.TB, testImage string, options ...ImageOption) sbom.SBOM {
    22  	t.Helper()
    23  	catalog := pkg.NewCollection()
    24  	var cfg imageCfg
    25  	var img *image.Image
    26  	for _, opt := range options {
    27  		opt(&cfg)
    28  	}
    29  
    30  	defer changeToDirectoryWithGoldenFixture(t, testImage)()
    31  
    32  	switch cfg.fromSnapshot {
    33  	case true:
    34  		img = imagetest.GetGoldenFixtureImage(t, testImage)
    35  	default:
    36  		img = imagetest.GetFixtureImage(t, "docker-archive", testImage)
    37  	}
    38  
    39  	populateImageCatalog(catalog, img)
    40  
    41  	// this is a hard coded value that is not given by the fixture helper and must be provided manually
    42  	img.Metadata.ManifestDigest = "sha256:2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368"
    43  
    44  	src := stereoscopesource.New(img, stereoscopesource.ImageConfig{
    45  		Reference: "user-image-input",
    46  	})
    47  
    48  	return sbom.SBOM{
    49  		Artifacts: sbom.Artifacts{
    50  			Packages: catalog,
    51  			LinuxDistribution: &linux.Release{
    52  				PrettyName: "debian",
    53  				Name:       "debian",
    54  				ID:         "debian",
    55  				IDLike:     []string{"like!"},
    56  				Version:    "1.2.3",
    57  				VersionID:  "1.2.3",
    58  			},
    59  		},
    60  		Source: src.Describe(),
    61  		Descriptor: sbom.Descriptor{
    62  			Name:    "syft",
    63  			Version: "v0.42.0-bogus",
    64  			// the application configuration should be persisted here, however, we do not want to import
    65  			// the application configuration in this package (it's reserved only for ingestion by the cmd package)
    66  			Configuration: map[string]string{
    67  				"config-key": "config-value",
    68  			},
    69  		},
    70  	}
    71  }
    72  
    73  func changeToDirectoryWithGoldenFixture(t testing.TB, testImage string) func() {
    74  	// check if test fixture exists... if not, check if there is a shared fixture relative to this dir
    75  	fn := func() {}
    76  
    77  	path := filepath.Join("test-fixtures", testImage)
    78  	if _, err := os.Stat(path); err != nil {
    79  		// change dir, restore as defer
    80  		wd, err := os.Getwd()
    81  		require.NoError(t, err)
    82  		fn = func() {
    83  			require.NoError(t, os.Chdir(wd))
    84  		}
    85  
    86  		// change dir to the testutil dir
    87  		require.NoError(t, os.Chdir(filepath.Join(wd, "..", "internal", "testutil")))
    88  		t.Cleanup(fn)
    89  
    90  		if _, err := os.Stat(path); err != nil {
    91  			t.Fatalf("unable to find test fixture: %s", path)
    92  		}
    93  	}
    94  	return fn
    95  }
    96  
    97  func populateImageCatalog(catalog *pkg.Collection, img *image.Image) {
    98  	// TODO: this helper function is coupled to the image-simple fixture, which seems like a bad idea
    99  	_, ref1, _ := img.SquashedTree().File("/somefile-1.txt", filetree.FollowBasenameLinks)
   100  	_, ref2, _ := img.SquashedTree().File("/somefile-2.txt", filetree.FollowBasenameLinks)
   101  
   102  	// populate catalog with test data
   103  	if ref1 != nil {
   104  		catalog.Add(pkg.Package{
   105  			Name:    "package-1",
   106  			Version: "1.0.1",
   107  			Locations: file.NewLocationSet(
   108  				file.NewLocationFromImage(string(ref1.RealPath), *ref1.Reference, img),
   109  			),
   110  			Type:     pkg.PythonPkg,
   111  			FoundBy:  "the-cataloger-1",
   112  			Language: pkg.Python,
   113  			Licenses: pkg.NewLicenseSet(
   114  				pkg.NewLicense("MIT"),
   115  			),
   116  			Metadata: pkg.PythonPackage{
   117  				Name:    "package-1",
   118  				Version: "1.0.1",
   119  			},
   120  			PURL: "a-purl-1", // intentionally a bad pURL for test fixtures
   121  			CPEs: []cpe.CPE{
   122  				cpe.Must("cpe:2.3:*:some:package:1:*:*:*:*:*:*:*", cpe.GeneratedSource),
   123  			},
   124  		})
   125  	}
   126  
   127  	if ref2 != nil {
   128  		catalog.Add(pkg.Package{
   129  			Name:    "package-2",
   130  			Version: "2.0.1",
   131  			Locations: file.NewLocationSet(
   132  				file.NewLocationFromImage(string(ref2.RealPath), *ref2.Reference, img),
   133  			),
   134  			Type:    pkg.DebPkg,
   135  			FoundBy: "the-cataloger-2",
   136  			Metadata: pkg.DpkgDBEntry{
   137  				Package: "package-2",
   138  				Version: "2.0.1",
   139  			},
   140  			PURL: "pkg:deb/debian/package-2@2.0.1",
   141  			CPEs: []cpe.CPE{
   142  				cpe.Must("cpe:2.3:*:some:package:2:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
   143  			},
   144  		})
   145  	}
   146  }