github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/syft/linux/identify_release_test.go (about) 1 package linux 2 3 import ( 4 "io" 5 "os" 6 "testing" 7 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 11 "github.com/anchore/syft/syft/source" 12 "github.com/anchore/syft/syft/source/directorysource" 13 ) 14 15 func TestIdentifyRelease(t *testing.T) { 16 tests := []struct { 17 fixture string 18 release *Release 19 }{ 20 { 21 fixture: "test-fixtures/os/alpine", 22 release: &Release{ 23 PrettyName: "Alpine Linux v3.11", 24 Name: "Alpine Linux", 25 ID: "alpine", 26 IDLike: nil, 27 VersionID: "3.11.6", 28 HomeURL: "https://alpinelinux.org/", 29 BugReportURL: "https://bugs.alpinelinux.org/", 30 }, 31 }, 32 { 33 fixture: "test-fixtures/os/amazon", 34 release: &Release{ 35 PrettyName: "Amazon Linux 2", 36 Name: "Amazon Linux", 37 ID: "amzn", 38 IDLike: []string{ 39 "centos", 40 "rhel", 41 "fedora", 42 }, 43 Version: "2", 44 VersionID: "2", 45 HomeURL: "https://amazonlinux.com/", 46 CPEName: "cpe:2.3:o:amazon:amazon_linux:2", 47 }, 48 }, 49 { 50 fixture: "test-fixtures/os/busybox", 51 release: &Release{ 52 PrettyName: "BusyBox v1.31.1", 53 Name: "busybox", 54 ID: "busybox", 55 IDLike: []string{"busybox"}, 56 Version: "1.31.1", 57 VersionID: "1.31.1", 58 }, 59 }, 60 { 61 fixture: "test-fixtures/os/centos", 62 release: &Release{ 63 PrettyName: "CentOS Linux 8 (Core)", 64 Name: "CentOS Linux", 65 ID: "centos", 66 IDLike: []string{"rhel", 67 "fedora", 68 }, 69 Version: "8 (Core)", 70 VersionID: "8", 71 HomeURL: "https://www.centos.org/", 72 BugReportURL: "https://bugs.centos.org/", 73 CPEName: "cpe:/o:centos:centos:8", 74 }, 75 }, 76 { 77 fixture: "test-fixtures/os/debian", 78 release: &Release{ 79 PrettyName: "Debian GNU/Linux 8 (jessie)", 80 Name: "Debian GNU/Linux", 81 ID: "debian", 82 IDLike: nil, 83 Version: "8 (jessie)", 84 VersionID: "8", 85 HomeURL: "http://www.debian.org/", 86 SupportURL: "http://www.debian.org/support", 87 BugReportURL: "https://bugs.debian.org/", 88 }, 89 }, 90 { 91 fixture: "test-fixtures/os/fedora", 92 release: &Release{ 93 PrettyName: "Fedora Linux 36 (Container Image)", 94 Name: "Fedora Linux", 95 ID: "fedora", 96 IDLike: nil, 97 Version: "36 (Container Image)", 98 VersionID: "36", 99 Variant: "Container Image", 100 VariantID: "container", 101 HomeURL: "https://fedoraproject.org/", 102 SupportURL: "https://ask.fedoraproject.org/", 103 BugReportURL: "https://bugzilla.redhat.com/", 104 PrivacyPolicyURL: "https://fedoraproject.org/wiki/Legal:PrivacyPolicy", 105 CPEName: "cpe:/o:fedoraproject:fedora:36", 106 SupportEnd: "2023-05-16", 107 }, 108 }, 109 { 110 fixture: "test-fixtures/os/redhat", 111 release: &Release{ 112 PrettyName: "Red Hat Enterprise Linux Server 7.3 (Maipo)", 113 Name: "Red Hat Enterprise Linux Server", 114 ID: "rhel", 115 IDLike: []string{"fedora"}, 116 Version: "7.3 (Maipo)", 117 VersionID: "7.3", 118 HomeURL: "https://www.redhat.com/", 119 BugReportURL: "https://bugzilla.redhat.com/", 120 CPEName: "cpe:/o:redhat:enterprise_linux:7.3:GA:server", 121 }, 122 }, 123 { 124 fixture: "test-fixtures/os/ubuntu", 125 release: &Release{ 126 PrettyName: "Ubuntu 20.04 LTS", 127 Name: "Ubuntu", 128 ID: "ubuntu", 129 IDLike: []string{"debian"}, 130 Version: "20.04 LTS (Focal Fossa)", 131 VersionCodename: "focal", 132 VersionID: "20.04", 133 HomeURL: "https://www.ubuntu.com/", 134 SupportURL: "https://help.ubuntu.com/", 135 BugReportURL: "https://bugs.launchpad.net/ubuntu/", 136 PrivacyPolicyURL: "https://www.ubuntu.com/legal/terms-and-policies/privacy-policy", 137 }, 138 }, 139 { 140 fixture: "test-fixtures/os/oraclelinux", 141 release: &Release{ 142 PrettyName: "Oracle Linux Server 8.3", 143 Name: "Oracle Linux Server", 144 ID: "ol", 145 IDLike: []string{"fedora"}, 146 Version: "8.3", 147 VersionID: "8.3", 148 Variant: "Server", 149 VariantID: "server", 150 HomeURL: "https://linux.oracle.com/", 151 BugReportURL: "https://bugzilla.oracle.com/", 152 CPEName: "cpe:/o:oracle:linux:8:3:server", 153 }, 154 }, 155 { 156 fixture: "test-fixtures/os/empty", 157 }, 158 { 159 fixture: "test-fixtures/os/custom", 160 release: &Release{ 161 PrettyName: "CentOS Linux 8 (Core)", 162 Name: "Scientific Linux", 163 ID: "scientific", 164 IDLike: []string{ 165 "rhel", 166 "fedora", 167 }, 168 Version: "16 (Core)", 169 VersionID: "8", 170 HomeURL: "https://www.centos.org/", 171 BugReportURL: "https://bugs.centos.org/", 172 CPEName: "cpe:/o:centos:centos:8", 173 }, 174 }, 175 { 176 fixture: "test-fixtures/os/opensuse-leap", 177 release: &Release{ 178 PrettyName: "openSUSE Leap 15.2", 179 Name: "openSUSE Leap", 180 ID: "opensuse-leap", 181 IDLike: []string{ 182 "suse", 183 "opensuse", 184 }, 185 Version: "15.2", 186 VersionID: "15.2", 187 HomeURL: "https://www.opensuse.org/", 188 BugReportURL: "https://bugs.opensuse.org", 189 CPEName: "cpe:/o:opensuse:leap:15.2", 190 }, 191 }, 192 { 193 fixture: "test-fixtures/os/sles", 194 release: &Release{ 195 PrettyName: "SUSE Linux Enterprise Server 15 SP2", 196 Name: "SLES", 197 ID: "sles", 198 IDLike: []string{"suse"}, 199 Version: "15-SP2", 200 VersionID: "15.2", 201 CPEName: "cpe:/o:suse:sles:15:sp2", 202 }, 203 }, 204 { 205 fixture: "test-fixtures/os/photon", 206 release: &Release{ 207 PrettyName: "VMware Photon OS/Linux", 208 Name: "VMware Photon OS", 209 ID: "photon", 210 IDLike: nil, 211 Version: "2.0", 212 VersionID: "2.0", 213 HomeURL: "https://vmware.github.io/photon/", 214 BugReportURL: "https://github.com/vmware/photon/issues", 215 }, 216 }, 217 { 218 fixture: "test-fixtures/os/arch", 219 release: &Release{ 220 PrettyName: "Arch Linux", 221 Name: "Arch Linux", 222 ID: "arch", 223 IDLike: nil, 224 BuildID: "rolling", 225 HomeURL: "https://www.archlinux.org/", 226 SupportURL: "https://bbs.archlinux.org/", 227 BugReportURL: "https://bugs.archlinux.org/", 228 }, 229 }, 230 { 231 fixture: "test-fixtures/partial-fields/missing-id", 232 release: &Release{ 233 Name: "Debian GNU/Linux", 234 IDLike: []string{"debian"}, 235 VersionID: "8", 236 }, 237 }, 238 { 239 fixture: "test-fixtures/partial-fields/unknown-id", 240 release: &Release{ 241 Name: "Debian GNU/Linux", 242 ID: "my-awesome-distro", 243 IDLike: []string{"debian"}, 244 VersionID: "8", 245 }, 246 }, 247 { 248 fixture: "test-fixtures/partial-fields/missing-version", 249 release: &Release{ 250 Name: "Debian GNU/Linux", 251 IDLike: []string{"debian"}, 252 }, 253 }, 254 { 255 fixture: "test-fixtures/os/centos6", 256 release: &Release{ 257 PrettyName: "centos", 258 Name: "centos", 259 ID: "centos", 260 IDLike: []string{"centos"}, 261 Version: "6", 262 VersionID: "6", 263 CPEName: "cpe:/o:centos:linux:6:GA", 264 }, 265 }, 266 { 267 fixture: "test-fixtures/os/centos5", 268 release: &Release{ 269 PrettyName: "CentOS", 270 Name: "centos", 271 ID: "centos", 272 IDLike: []string{"centos"}, 273 Version: "5.7", 274 VersionID: "5.7", 275 }, 276 }, 277 { 278 fixture: "test-fixtures/os/mariner", 279 release: &Release{ 280 PrettyName: "CBL-Mariner/Linux", 281 Name: "Common Base Linux Mariner", 282 ID: "mariner", 283 IDLike: nil, 284 Version: "1.0.20210901", 285 VersionID: "1.0", 286 HomeURL: "https://aka.ms/cbl-mariner", 287 SupportURL: "https://aka.ms/cbl-mariner", 288 BugReportURL: "https://aka.ms/cbl-mariner", 289 }, 290 }, 291 { 292 fixture: "test-fixtures/os/rockylinux", 293 release: &Release{ 294 PrettyName: "Rocky Linux 8.4 (Green Obsidian)", 295 Name: "Rocky Linux", 296 ID: "rocky", 297 IDLike: []string{ 298 "rhel", 299 "fedora", 300 }, 301 Version: "8.4 (Green Obsidian)", 302 VersionID: "8.4", 303 HomeURL: "https://rockylinux.org/", 304 BugReportURL: "https://bugs.rockylinux.org/", 305 CPEName: "cpe:/o:rocky:rocky:8.4:GA", 306 }, 307 }, 308 { 309 fixture: "test-fixtures/os/almalinux", 310 release: &Release{ 311 PrettyName: "AlmaLinux 8.4 (Electric Cheetah)", 312 Name: "AlmaLinux", 313 ID: "almalinux", 314 IDLike: []string{ 315 "rhel", 316 "centos", 317 "fedora", 318 }, 319 Version: "8.4 (Electric Cheetah)", 320 VersionID: "8.4", 321 HomeURL: "https://almalinux.org/", 322 BugReportURL: "https://bugs.almalinux.org/", 323 CPEName: "cpe:/o:almalinux:almalinux:8.4:GA", 324 }, 325 }, 326 { 327 fixture: "test-fixtures/os/wolfi", 328 release: &Release{ 329 PrettyName: "Wolfi", 330 Name: "Wolfi", 331 ID: "wolfi", 332 VersionID: "20220914", 333 HomeURL: "https://wolfi.dev", 334 }, 335 }, 336 } 337 338 for _, test := range tests { 339 t.Run(test.fixture, func(t *testing.T) { 340 s, err := directorysource.New(directorysource.Config{ 341 Path: test.fixture, 342 }) 343 require.NoError(t, err) 344 345 resolver, err := s.FileResolver(source.SquashedScope) 346 require.NoError(t, err) 347 348 assert.Equal(t, test.release, IdentifyRelease(resolver)) 349 }) 350 } 351 } 352 353 func TestParseOsRelease(t *testing.T) { 354 355 tests := []struct { 356 fixture string 357 release *Release 358 }{ 359 { 360 fixture: "test-fixtures/ubuntu-20.04", 361 362 release: &Release{ 363 PrettyName: "Ubuntu 20.04 LTS", 364 Name: "Ubuntu", 365 ID: "ubuntu", 366 IDLike: []string{"debian"}, 367 Version: "20.04 LTS (Focal Fossa)", 368 VersionID: "20.04", 369 VersionCodename: "focal", 370 HomeURL: "https://www.ubuntu.com/", 371 SupportURL: "https://help.ubuntu.com/", 372 BugReportURL: "https://bugs.launchpad.net/ubuntu/", 373 PrivacyPolicyURL: "https://www.ubuntu.com/legal/terms-and-policies/privacy-policy", 374 }, 375 }, 376 377 { 378 fixture: "test-fixtures/debian-8", 379 380 release: &Release{ 381 PrettyName: "Debian GNU/Linux 8 (jessie)", 382 Name: "Debian GNU/Linux", 383 ID: "debian", 384 IDLike: nil, 385 Version: "8 (jessie)", 386 VersionID: "8", 387 HomeURL: "http://www.debian.org/", 388 SupportURL: "http://www.debian.org/support", 389 BugReportURL: "https://bugs.debian.org/", 390 }, 391 }, 392 393 { 394 fixture: "test-fixtures/centos-8", 395 396 release: &Release{ 397 PrettyName: "CentOS Linux 8 (Core)", 398 Name: "CentOS Linux", 399 ID: "centos", 400 IDLike: []string{ 401 "rhel", 402 "fedora", 403 }, 404 Version: "8 (Core)", 405 VersionID: "8", 406 HomeURL: "https://www.centos.org/", 407 BugReportURL: "https://bugs.centos.org/", 408 CPEName: "cpe:/o:centos:centos:8", 409 }, 410 }, 411 412 { 413 fixture: "test-fixtures/rhel-8", 414 415 release: &Release{ 416 PrettyName: "Red Hat Enterprise Linux 8.1 (Ootpa)", 417 Name: "Red Hat Enterprise Linux", 418 ID: "rhel", 419 IDLike: []string{"fedora"}, 420 Version: "8.1 (Ootpa)", 421 VersionID: "8.1", 422 HomeURL: "https://www.redhat.com/", 423 BugReportURL: "https://bugzilla.redhat.com/", 424 CPEName: "cpe:/o:redhat:enterprise_linux:8.1:GA", 425 }, 426 }, 427 428 { 429 fixture: "test-fixtures/unprintable", 430 431 release: &Release{ 432 PrettyName: "Debian GNU/Linux 8 (jessie)", 433 Name: "Debian GNU/Linux", 434 ID: "debian", 435 IDLike: nil, 436 Version: "8 (jessie)", 437 VersionID: "8", 438 HomeURL: "http://www.debian.org/", 439 SupportURL: "http://www.debian.org/support", 440 BugReportURL: "https://bugs.debian.org/", 441 }, 442 }, 443 } 444 445 for _, test := range tests { 446 t.Run(test.fixture, 447 func(t *testing.T) { 448 release, 449 err := parseOsRelease(retrieveFixtureContentsAsString(test.fixture, 450 t)) 451 require.NoError(t, 452 err) 453 assert.Equal(t, 454 test.release, 455 release) 456 }) 457 } 458 459 } 460 461 func TestParseSystemReleaseCPE(t *testing.T) { 462 tests := []struct { 463 fixture string 464 release *Release 465 }{ 466 { 467 fixture: "test-fixtures/os/centos6/etc/system-release-cpe", 468 release: &Release{ 469 PrettyName: "centos", 470 Name: "centos", 471 ID: "centos", 472 IDLike: []string{"centos"}, 473 Version: "6", 474 VersionID: "6", 475 CPEName: "cpe:/o:centos:linux:6:GA", 476 }, 477 }, 478 { 479 fixture: "test-fixtures/bad-system-release-cpe", 480 release: nil, 481 }, 482 } 483 484 for _, test := range tests { 485 t.Run(test.fixture, func(t *testing.T) { 486 contents := retrieveFixtureContentsAsString(test.fixture, t) 487 release, err := parseSystemReleaseCPE(contents) 488 require.NoError(t, err) 489 if test.release == nil { 490 assert.Nil(t, release) 491 return 492 } 493 494 assert.Equal(t, test.release, release) 495 }) 496 } 497 } 498 499 func TestParseRedhatRelease(t *testing.T) { 500 tests := []struct { 501 fixture string 502 name string 503 release *Release 504 }{ 505 { 506 fixture: "test-fixtures/os/centos5/etc/redhat-release", 507 name: "Centos 5", 508 release: &Release{ 509 PrettyName: "CentOS", 510 Name: "centos", 511 ID: "centos", 512 IDLike: []string{"centos"}, 513 Version: "5.7", 514 VersionID: "5.7", 515 }, 516 }, 517 { 518 fixture: "test-fixtures/bad-redhat-release", 519 name: "Centos 5 Bad Redhat Release", 520 release: nil, 521 }, 522 } 523 524 for _, test := range tests { 525 t.Run(test.name, func(t *testing.T) { 526 release, err := parseRedhatRelease(retrieveFixtureContentsAsString(test.fixture, t)) 527 require.NoError(t, err) 528 if test.release == nil { 529 assert.Nil(t, release) 530 return 531 } 532 533 assert.Equal(t, test.release, release) 534 }) 535 } 536 } 537 538 func retrieveFixtureContentsAsString(fixturePath string, t *testing.T) string { 539 fixture, err := os.Open(fixturePath) 540 if err != nil { 541 t.Fatalf("could not open test fixture=%s: %+v", fixturePath, err) 542 } 543 defer fixture.Close() 544 545 b, err := io.ReadAll(fixture) 546 if err != nil { 547 t.Fatalf("unable to read fixture file: %+v", err) 548 } 549 550 return string(b) 551 }