github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/formats/syftjson/decoder_test.go (about) 1 package syftjson 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "strings" 8 "testing" 9 10 "github.com/go-test/deep" 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 14 stereoscopeFile "github.com/anchore/stereoscope/pkg/file" 15 "github.com/anchore/syft/internal" 16 "github.com/anchore/syft/syft/cpe" 17 "github.com/anchore/syft/syft/file" 18 "github.com/anchore/syft/syft/formats/internal/testutils" 19 "github.com/anchore/syft/syft/linux" 20 "github.com/anchore/syft/syft/pkg" 21 "github.com/anchore/syft/syft/sbom" 22 "github.com/anchore/syft/syft/source" 23 ) 24 25 func TestEncodeDecodeCycle(t *testing.T) { 26 testImage := "image-simple" 27 originalSBOM := testutils.ImageInput(t, testImage) 28 29 var buf bytes.Buffer 30 assert.NoError(t, encoder(&buf, originalSBOM)) 31 32 actualSBOM, err := decoder(bytes.NewReader(buf.Bytes())) 33 assert.NoError(t, err) 34 35 for _, d := range deep.Equal(originalSBOM.Source, actualSBOM.Source) { 36 if strings.HasSuffix(d, "<nil slice> != []") { 37 // semantically the same 38 continue 39 } 40 t.Errorf("metadata difference: %+v", d) 41 } 42 43 actualPackages := actualSBOM.Artifacts.Packages.Sorted() 44 for idx, p := range originalSBOM.Artifacts.Packages.Sorted() { 45 if !assert.Equal(t, p.Name, actualPackages[idx].Name) { 46 t.Errorf("different package at idx=%d: %s vs %s", idx, p.Name, actualPackages[idx].Name) 47 continue 48 } 49 50 for _, d := range deep.Equal(p, actualPackages[idx]) { 51 if strings.Contains(d, ".VirtualPath: ") { 52 // location.Virtual path is not exposed in the json output 53 continue 54 } 55 if strings.HasSuffix(d, "<nil slice> != []") { 56 // semantically the same 57 continue 58 } 59 t.Errorf("package difference (%s): %+v", p.Name, d) 60 } 61 } 62 } 63 64 func TestOutOfDateParser(t *testing.T) { 65 tests := []struct { 66 name string 67 documentVersion string 68 parserVersion string 69 want error 70 }{{ 71 name: "no warning when doc version is older", 72 documentVersion: "1.0.9", 73 parserVersion: "3.1.0", 74 }, { 75 name: "warning when parser is older", 76 documentVersion: "4.3.2", 77 parserVersion: "3.1.0", 78 want: fmt.Errorf("document has schema version %s, but parser has older schema version (%s)", "4.3.2", "3.1.0"), 79 }, { 80 name: "warning when document version is unparseable", 81 documentVersion: "some-nonsense", 82 parserVersion: "3.1.0", 83 want: fmt.Errorf("error comparing document schema version with parser schema version: %w", errors.New("Invalid Semantic Version")), 84 }, { 85 name: "warning when parser version is unparseable", 86 documentVersion: "7.1.0", 87 parserVersion: "some-nonsense", 88 want: fmt.Errorf("error comparing document schema version with parser schema version: %w", errors.New("Invalid Semantic Version")), 89 }} 90 91 for _, tt := range tests { 92 t.Run(tt.name, func(t *testing.T) { 93 got := checkSupportedSchema(tt.documentVersion, tt.parserVersion) 94 assert.Equal(t, tt.want, got) 95 }) 96 } 97 } 98 99 func Test_encodeDecodeFileMetadata(t *testing.T) { 100 p := pkg.Package{ 101 Name: "pkg", 102 Version: "version", 103 FoundBy: "something", 104 Locations: file.NewLocationSet(file.Location{ 105 LocationData: file.LocationData{ 106 Coordinates: file.Coordinates{ 107 RealPath: "/somewhere", 108 FileSystemID: "id", 109 }, 110 }, 111 LocationMetadata: file.LocationMetadata{ 112 Annotations: map[string]string{ 113 "key": "value", 114 }, 115 }, 116 }), 117 Licenses: pkg.NewLicenseSet(pkg.License{ 118 Value: "MIT", 119 SPDXExpression: "MIT", 120 Type: "MIT", 121 URLs: internal.NewStringSet("https://example.org/license"), 122 Locations: file.LocationSet{}, 123 }), 124 Language: "language", 125 Type: "type", 126 CPEs: []cpe.CPE{ 127 { 128 Part: "a", 129 Vendor: "vendor", 130 Product: "product", 131 Version: "version", 132 Update: "update", 133 }, 134 }, 135 PURL: "pkg:generic/pkg@version", 136 MetadataType: "", 137 Metadata: nil, 138 } 139 p.SetID() 140 141 c := file.Coordinates{ 142 RealPath: "some-file", 143 FileSystemID: "some-fs-id", 144 } 145 146 s := sbom.SBOM{ 147 Artifacts: sbom.Artifacts{ 148 Packages: pkg.NewCollection(p), 149 FileMetadata: map[file.Coordinates]file.Metadata{ 150 c: { 151 FileInfo: stereoscopeFile.ManualInfo{ 152 NameValue: c.RealPath, 153 ModeValue: 0644, 154 SizeValue: 7, 155 }, 156 Path: c.RealPath, 157 Type: stereoscopeFile.TypeRegular, 158 UserID: 1, 159 GroupID: 2, 160 MIMEType: "text/plain", 161 }, 162 }, 163 FileDigests: map[file.Coordinates][]file.Digest{ 164 c: { 165 { 166 Algorithm: "sha1", 167 Value: "d34db33f", 168 }, 169 }, 170 }, 171 FileContents: map[file.Coordinates]string{ 172 c: "some contents", 173 }, 174 FileLicenses: map[file.Coordinates][]file.License{ 175 c: { 176 { 177 Value: "MIT", 178 SPDXExpression: "MIT", 179 Type: "MIT", 180 LicenseEvidence: &file.LicenseEvidence{ 181 Confidence: 1, 182 Offset: 2, 183 Extent: 3, 184 }, 185 }, 186 }, 187 }, 188 LinuxDistribution: &linux.Release{ 189 PrettyName: "some os", 190 Name: "os", 191 ID: "os-id", 192 IDLike: []string{"os"}, 193 Version: "version", 194 VersionID: "version", 195 VersionCodename: "codename", 196 BuildID: "build-id", 197 ImageID: "image-id", 198 ImageVersion: "image-version", 199 Variant: "variant", 200 VariantID: "variant-id", 201 HomeURL: "https://example.org/os", 202 SupportURL: "https://example.org/os/support", 203 BugReportURL: "https://example.org/os/bugs", 204 PrivacyPolicyURL: "https://example.org/os/privacy", 205 CPEName: "os-cpe", 206 SupportEnd: "now", 207 }, 208 }, 209 Relationships: nil, 210 Source: source.Description{ 211 ID: "some-id", 212 Name: "some-name", 213 Version: "some-version", 214 Metadata: source.FileSourceMetadata{ 215 Path: "/some-file-source-path", 216 Digests: []file.Digest{ 217 { 218 Algorithm: "sha1", 219 Value: "d34db33f", 220 }, 221 }, 222 MIMEType: "file/zip", 223 }, 224 }, 225 Descriptor: sbom.Descriptor{ 226 Name: "syft", 227 Version: "this-version", 228 }, 229 } 230 231 buf := &bytes.Buffer{} 232 err := encoder(buf, s) 233 require.NoError(t, err) 234 235 got, err := decoder(buf) 236 require.NoError(t, err) 237 238 require.Equal(t, s, *got) 239 }