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 }