github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/formats/syftjson/encoder_test.go (about)

     1  package syftjson
     2  
     3  import (
     4  	"flag"
     5  	"testing"
     6  
     7  	stereoFile "github.com/anchore/stereoscope/pkg/file"
     8  	"github.com/anchore/syft/syft/artifact"
     9  	"github.com/anchore/syft/syft/cpe"
    10  	"github.com/anchore/syft/syft/file"
    11  	"github.com/anchore/syft/syft/formats/internal/testutils"
    12  	"github.com/anchore/syft/syft/linux"
    13  	"github.com/anchore/syft/syft/pkg"
    14  	"github.com/anchore/syft/syft/sbom"
    15  	"github.com/anchore/syft/syft/source"
    16  )
    17  
    18  var updateSnapshot = flag.Bool("update-json", false, "update the *.golden files for json encoders")
    19  var updateImage = flag.Bool("update-image", false, "update the golden image used for image encoder testing")
    20  
    21  func TestDirectoryEncoder(t *testing.T) {
    22  	dir := t.TempDir()
    23  	testutils.AssertEncoderAgainstGoldenSnapshot(t,
    24  		testutils.EncoderSnapshotTestConfig{
    25  			Subject:                     testutils.DirectoryInput(t, dir),
    26  			Format:                      Format(),
    27  			UpdateSnapshot:              *updateSnapshot,
    28  			PersistRedactionsInSnapshot: true,
    29  			IsJSON:                      true,
    30  			Redactor:                    redactor(dir),
    31  		},
    32  	)
    33  }
    34  
    35  func TestImageEncoder(t *testing.T) {
    36  	testImage := "image-simple"
    37  	testutils.AssertEncoderAgainstGoldenImageSnapshot(t,
    38  		testutils.ImageSnapshotTestConfig{
    39  			Image:               testImage,
    40  			UpdateImageSnapshot: *updateImage,
    41  		},
    42  		testutils.EncoderSnapshotTestConfig{
    43  			Subject:                     testutils.ImageInput(t, testImage, testutils.FromSnapshot()),
    44  			Format:                      Format(),
    45  			UpdateSnapshot:              *updateSnapshot,
    46  			PersistRedactionsInSnapshot: true,
    47  			IsJSON:                      true,
    48  			Redactor:                    redactor(),
    49  		},
    50  	)
    51  }
    52  
    53  func TestEncodeFullJSONDocument(t *testing.T) {
    54  	catalog := pkg.NewCollection()
    55  
    56  	p1 := pkg.Package{
    57  		Name:    "package-1",
    58  		Version: "1.0.1",
    59  		Locations: file.NewLocationSet(
    60  			file.NewLocationFromCoordinates(file.Coordinates{
    61  				RealPath: "/a/place/a",
    62  			}),
    63  		),
    64  		Type:         pkg.PythonPkg,
    65  		FoundBy:      "the-cataloger-1",
    66  		Language:     pkg.Python,
    67  		MetadataType: pkg.PythonPackageMetadataType,
    68  		Licenses:     pkg.NewLicenseSet(pkg.NewLicense("MIT")),
    69  		Metadata: pkg.PythonPackageMetadata{
    70  			Name:    "package-1",
    71  			Version: "1.0.1",
    72  			Files:   []pkg.PythonFileRecord{},
    73  		},
    74  		PURL: "a-purl-1",
    75  		CPEs: []cpe.CPE{
    76  			cpe.Must("cpe:2.3:*:some:package:1:*:*:*:*:*:*:*"),
    77  		},
    78  	}
    79  
    80  	p2 := pkg.Package{
    81  		Name:    "package-2",
    82  		Version: "2.0.1",
    83  		Locations: file.NewLocationSet(
    84  			file.NewLocationFromCoordinates(file.Coordinates{
    85  				RealPath: "/b/place/b",
    86  			}),
    87  		),
    88  		Type:         pkg.DebPkg,
    89  		FoundBy:      "the-cataloger-2",
    90  		MetadataType: pkg.DpkgMetadataType,
    91  		Metadata: pkg.DpkgMetadata{
    92  			Package: "package-2",
    93  			Version: "2.0.1",
    94  			Files:   []pkg.DpkgFileRecord{},
    95  		},
    96  		PURL: "a-purl-2",
    97  		CPEs: []cpe.CPE{
    98  			cpe.Must("cpe:2.3:*:some:package:2:*:*:*:*:*:*:*"),
    99  		},
   100  	}
   101  
   102  	catalog.Add(p1)
   103  	catalog.Add(p2)
   104  
   105  	s := sbom.SBOM{
   106  		Artifacts: sbom.Artifacts{
   107  			Packages: catalog,
   108  			FileMetadata: map[file.Coordinates]file.Metadata{
   109  				file.NewLocation("/a/place").Coordinates: {
   110  					FileInfo: stereoFile.ManualInfo{
   111  						NameValue: "/a/place",
   112  						ModeValue: 0775,
   113  					},
   114  					Type:    stereoFile.TypeDirectory,
   115  					UserID:  0,
   116  					GroupID: 0,
   117  				},
   118  				file.NewLocation("/a/place/a").Coordinates: {
   119  					FileInfo: stereoFile.ManualInfo{
   120  						NameValue: "/a/place/a",
   121  						ModeValue: 0775,
   122  					},
   123  					Type:    stereoFile.TypeRegular,
   124  					UserID:  0,
   125  					GroupID: 0,
   126  				},
   127  				file.NewLocation("/b").Coordinates: {
   128  					FileInfo: stereoFile.ManualInfo{
   129  						NameValue: "/b",
   130  						ModeValue: 0775,
   131  					},
   132  					Type:            stereoFile.TypeSymLink,
   133  					LinkDestination: "/c",
   134  					UserID:          0,
   135  					GroupID:         0,
   136  				},
   137  				file.NewLocation("/b/place/b").Coordinates: {
   138  					FileInfo: stereoFile.ManualInfo{
   139  						NameValue: "/b/place/b",
   140  						ModeValue: 0644,
   141  					},
   142  					Type:    stereoFile.TypeRegular,
   143  					UserID:  1,
   144  					GroupID: 2,
   145  				},
   146  			},
   147  			FileDigests: map[file.Coordinates][]file.Digest{
   148  				file.NewLocation("/a/place/a").Coordinates: {
   149  					{
   150  						Algorithm: "sha256",
   151  						Value:     "366a3f5653e34673b875891b021647440d0127c2ef041e3b1a22da2a7d4f3703",
   152  					},
   153  				},
   154  				file.NewLocation("/b/place/b").Coordinates: {
   155  					{
   156  						Algorithm: "sha256",
   157  						Value:     "1b3722da2a7d90d033b87581a2a3f12021647445653e34666ef041e3b4f3707c",
   158  					},
   159  				},
   160  			},
   161  			FileContents: map[file.Coordinates]string{
   162  				file.NewLocation("/a/place/a").Coordinates: "the-contents",
   163  			},
   164  			LinuxDistribution: &linux.Release{
   165  				ID:        "redhat",
   166  				Version:   "7",
   167  				VersionID: "7",
   168  				IDLike: []string{
   169  					"rhel",
   170  				},
   171  			},
   172  		},
   173  		Relationships: []artifact.Relationship{
   174  			{
   175  				From: p1,
   176  				To:   p2,
   177  				Type: artifact.OwnershipByFileOverlapRelationship,
   178  				Data: map[string]string{
   179  					"file": "path",
   180  				},
   181  			},
   182  		},
   183  		Source: source.Description{
   184  			ID: "c2b46b4eb06296933b7cf0722683964e9ecbd93265b9ef6ae9642e3952afbba0",
   185  			Metadata: source.StereoscopeImageSourceMetadata{
   186  				UserInput:      "user-image-input",
   187  				ID:             "sha256:c2b46b4eb06296933b7cf0722683964e9ecbd93265b9ef6ae9642e3952afbba0",
   188  				ManifestDigest: "sha256:2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368",
   189  				MediaType:      "application/vnd.docker.distribution.manifest.v2+json",
   190  				Tags: []string{
   191  					"stereoscope-fixture-image-simple:85066c51088bdd274f7a89e99e00490f666c49e72ffc955707cd6e18f0e22c5b",
   192  				},
   193  				Size: 38,
   194  				Layers: []source.StereoscopeLayerMetadata{
   195  					{
   196  						MediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip",
   197  						Digest:    "sha256:3de16c5b8659a2e8d888b8ded8427be7a5686a3c8c4e4dd30de20f362827285b",
   198  						Size:      22,
   199  					},
   200  					{
   201  						MediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip",
   202  						Digest:    "sha256:366a3f5653e34673b875891b021647440d0127c2ef041e3b1a22da2a7d4f3703",
   203  						Size:      16,
   204  					},
   205  				},
   206  				RawManifest: []byte("eyJzY2hlbWFWZXJzaW9uIjoyLCJtZWRpYVR5cGUiOiJh..."),
   207  				RawConfig:   []byte("eyJhcmNoaXRlY3R1cmUiOiJhbWQ2NCIsImNvbmZp..."),
   208  				RepoDigests: []string{},
   209  			},
   210  		},
   211  		Descriptor: sbom.Descriptor{
   212  			Name:    "syft",
   213  			Version: "v0.42.0-bogus",
   214  			// the application configuration should be persisted here, however, we do not want to import
   215  			// the application configuration in this package (it's reserved only for ingestion by the cmd package)
   216  			Configuration: map[string]string{
   217  				"config-key": "config-value",
   218  			},
   219  		},
   220  	}
   221  
   222  	testutils.AssertEncoderAgainstGoldenSnapshot(t,
   223  		testutils.EncoderSnapshotTestConfig{
   224  			Subject:                     s,
   225  			Format:                      Format(),
   226  			UpdateSnapshot:              *updateSnapshot,
   227  			PersistRedactionsInSnapshot: true,
   228  			IsJSON:                      true,
   229  			Redactor:                    redactor(),
   230  		},
   231  	)
   232  }
   233  
   234  func redactor(values ...string) testutils.Redactor {
   235  	return testutils.NewRedactions().
   236  		WithValuesRedacted(values...).
   237  		WithPatternRedactors(
   238  			map[string]string{
   239  				// remove schema version (don't even show the key or value)
   240  				`,?\s*"schema":\s*\{[^}]*}`: "",
   241  			},
   242  		)
   243  }