github.com/anchore/syft@v1.38.2/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/from-os-release",
   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/redhat/from-redhat-release",
   125  			release: &Release{
   126  				PrettyName: "Red Hat Enterprise Linux release 8.10 (Ootpa)",
   127  				Name:       "Red Hat Enterprise Linux",
   128  				ID:         "rhel",
   129  				IDLike:     []string{"rhel"},
   130  				Version:    "8.10 (Ootpa)",
   131  				VersionID:  "8.10",
   132  			},
   133  		},
   134  		{
   135  			fixture: "test-fixtures/os/ubuntu",
   136  			release: &Release{
   137  				PrettyName:       "Ubuntu 20.04 LTS",
   138  				Name:             "Ubuntu",
   139  				ID:               "ubuntu",
   140  				IDLike:           []string{"debian"},
   141  				Version:          "20.04 LTS (Focal Fossa)",
   142  				VersionCodename:  "focal",
   143  				VersionID:        "20.04",
   144  				HomeURL:          "https://www.ubuntu.com/",
   145  				SupportURL:       "https://help.ubuntu.com/",
   146  				BugReportURL:     "https://bugs.launchpad.net/ubuntu/",
   147  				PrivacyPolicyURL: "https://www.ubuntu.com/legal/terms-and-policies/privacy-policy",
   148  			},
   149  		},
   150  		{
   151  			fixture: "test-fixtures/os/oraclelinux",
   152  			release: &Release{
   153  				PrettyName:   "Oracle Linux Server 8.3",
   154  				Name:         "Oracle Linux Server",
   155  				ID:           "ol",
   156  				IDLike:       []string{"fedora"},
   157  				Version:      "8.3",
   158  				VersionID:    "8.3",
   159  				Variant:      "Server",
   160  				VariantID:    "server",
   161  				HomeURL:      "https://linux.oracle.com/",
   162  				BugReportURL: "https://bugzilla.oracle.com/",
   163  				CPEName:      "cpe:/o:oracle:linux:8:3:server",
   164  			},
   165  		},
   166  		{
   167  			fixture: "test-fixtures/os/empty",
   168  		},
   169  		{
   170  			fixture: "test-fixtures/os/custom",
   171  			release: &Release{
   172  				PrettyName: "CentOS Linux 8 (Core)",
   173  				Name:       "Scientific Linux",
   174  				ID:         "scientific",
   175  				IDLike: []string{
   176  					"rhel",
   177  					"fedora",
   178  				},
   179  				Version:      "16 (Core)",
   180  				VersionID:    "8",
   181  				HomeURL:      "https://www.centos.org/",
   182  				BugReportURL: "https://bugs.centos.org/",
   183  				CPEName:      "cpe:/o:centos:centos:8",
   184  			},
   185  		},
   186  		{
   187  			fixture: "test-fixtures/os/opensuse-leap",
   188  			release: &Release{
   189  				PrettyName: "openSUSE Leap 15.2",
   190  				Name:       "openSUSE Leap",
   191  				ID:         "opensuse-leap",
   192  				IDLike: []string{
   193  					"suse",
   194  					"opensuse",
   195  				},
   196  				Version:      "15.2",
   197  				VersionID:    "15.2",
   198  				HomeURL:      "https://www.opensuse.org/",
   199  				BugReportURL: "https://bugs.opensuse.org",
   200  				CPEName:      "cpe:/o:opensuse:leap:15.2",
   201  			},
   202  		},
   203  		{
   204  			fixture: "test-fixtures/os/sles",
   205  			release: &Release{
   206  				PrettyName: "SUSE Linux Enterprise Server 15 SP2",
   207  				Name:       "SLES",
   208  				ID:         "sles",
   209  				IDLike:     []string{"suse"},
   210  				Version:    "15-SP2",
   211  				VersionID:  "15.2",
   212  				CPEName:    "cpe:/o:suse:sles:15:sp2",
   213  			},
   214  		},
   215  		{
   216  			fixture: "test-fixtures/os/photon",
   217  			release: &Release{
   218  				PrettyName:   "VMware Photon OS/Linux",
   219  				Name:         "VMware Photon OS",
   220  				ID:           "photon",
   221  				IDLike:       nil,
   222  				Version:      "2.0",
   223  				VersionID:    "2.0",
   224  				HomeURL:      "https://vmware.github.io/photon/",
   225  				BugReportURL: "https://github.com/vmware/photon/issues",
   226  			},
   227  		},
   228  		{
   229  			fixture: "test-fixtures/os/arch",
   230  			release: &Release{
   231  				PrettyName:   "Arch Linux",
   232  				Name:         "Arch Linux",
   233  				ID:           "arch",
   234  				IDLike:       nil,
   235  				BuildID:      "rolling",
   236  				HomeURL:      "https://www.archlinux.org/",
   237  				SupportURL:   "https://bbs.archlinux.org/",
   238  				BugReportURL: "https://bugs.archlinux.org/",
   239  			},
   240  		},
   241  		{
   242  			fixture: "test-fixtures/partial-fields/missing-id",
   243  			release: &Release{
   244  				Name:      "Debian GNU/Linux",
   245  				IDLike:    []string{"debian"},
   246  				VersionID: "8",
   247  			},
   248  		},
   249  		{
   250  			fixture: "test-fixtures/partial-fields/unknown-id",
   251  			release: &Release{
   252  				Name:      "Debian GNU/Linux",
   253  				ID:        "my-awesome-distro",
   254  				IDLike:    []string{"debian"},
   255  				VersionID: "8",
   256  			},
   257  		},
   258  		{
   259  			fixture: "test-fixtures/partial-fields/missing-version",
   260  			release: &Release{
   261  				Name:   "Debian GNU/Linux",
   262  				IDLike: []string{"debian"},
   263  			},
   264  		},
   265  		{
   266  			fixture: "test-fixtures/os/centos6",
   267  			release: &Release{
   268  				PrettyName: "centos",
   269  				Name:       "centos",
   270  				ID:         "centos",
   271  				IDLike:     []string{"centos"},
   272  				Version:    "6",
   273  				VersionID:  "6",
   274  				CPEName:    "cpe:/o:centos:linux:6:GA",
   275  			},
   276  		},
   277  		{
   278  			fixture: "test-fixtures/os/centos5",
   279  			release: &Release{
   280  				PrettyName: "CentOS release 5.7 (Final)",
   281  				Name:       "CentOS",
   282  				ID:         "centos",
   283  				IDLike:     []string{"centos"},
   284  				Version:    "5.7",
   285  				VersionID:  "5.7",
   286  			},
   287  		},
   288  		{
   289  			fixture: "test-fixtures/os/mariner",
   290  			release: &Release{
   291  				PrettyName:   "CBL-Mariner/Linux",
   292  				Name:         "Common Base Linux Mariner",
   293  				ID:           "mariner",
   294  				IDLike:       nil,
   295  				Version:      "1.0.20210901",
   296  				VersionID:    "1.0",
   297  				HomeURL:      "https://aka.ms/cbl-mariner",
   298  				SupportURL:   "https://aka.ms/cbl-mariner",
   299  				BugReportURL: "https://aka.ms/cbl-mariner",
   300  			},
   301  		},
   302  		{
   303  			fixture: "test-fixtures/os/rockylinux",
   304  			release: &Release{
   305  				PrettyName: "Rocky Linux 8.4 (Green Obsidian)",
   306  				Name:       "Rocky Linux",
   307  				ID:         "rocky",
   308  				IDLike: []string{
   309  					"rhel",
   310  					"fedora",
   311  				},
   312  				Version:      "8.4 (Green Obsidian)",
   313  				VersionID:    "8.4",
   314  				HomeURL:      "https://rockylinux.org/",
   315  				BugReportURL: "https://bugs.rockylinux.org/",
   316  				CPEName:      "cpe:/o:rocky:rocky:8.4:GA",
   317  			},
   318  		},
   319  		{
   320  			fixture: "test-fixtures/os/almalinux",
   321  			release: &Release{
   322  				PrettyName: "AlmaLinux 8.4 (Electric Cheetah)",
   323  				Name:       "AlmaLinux",
   324  				ID:         "almalinux",
   325  				IDLike: []string{
   326  					"rhel",
   327  					"centos",
   328  					"fedora",
   329  				},
   330  				Version:      "8.4 (Electric Cheetah)",
   331  				VersionID:    "8.4",
   332  				HomeURL:      "https://almalinux.org/",
   333  				BugReportURL: "https://bugs.almalinux.org/",
   334  				CPEName:      "cpe:/o:almalinux:almalinux:8.4:GA",
   335  			},
   336  		},
   337  		{
   338  			fixture: "test-fixtures/os/wolfi",
   339  			release: &Release{
   340  				PrettyName: "Wolfi",
   341  				Name:       "Wolfi",
   342  				ID:         "wolfi",
   343  				VersionID:  "20220914",
   344  				HomeURL:    "https://wolfi.dev",
   345  			},
   346  		},
   347  	}
   348  
   349  	for _, test := range tests {
   350  		t.Run(test.fixture, func(t *testing.T) {
   351  			s, err := directorysource.New(directorysource.Config{
   352  				Path: test.fixture,
   353  			})
   354  			require.NoError(t, err)
   355  
   356  			resolver, err := s.FileResolver(source.SquashedScope)
   357  			require.NoError(t, err)
   358  
   359  			assert.Equal(t, test.release, IdentifyRelease(resolver))
   360  		})
   361  	}
   362  }
   363  
   364  func TestParseOsRelease(t *testing.T) {
   365  
   366  	tests := []struct {
   367  		fixture string
   368  		release *Release
   369  	}{
   370  		{
   371  			fixture: "test-fixtures/ubuntu-20.04",
   372  
   373  			release: &Release{
   374  				PrettyName:       "Ubuntu 20.04 LTS",
   375  				Name:             "Ubuntu",
   376  				ID:               "ubuntu",
   377  				IDLike:           []string{"debian"},
   378  				Version:          "20.04 LTS (Focal Fossa)",
   379  				VersionID:        "20.04",
   380  				VersionCodename:  "focal",
   381  				HomeURL:          "https://www.ubuntu.com/",
   382  				SupportURL:       "https://help.ubuntu.com/",
   383  				BugReportURL:     "https://bugs.launchpad.net/ubuntu/",
   384  				PrivacyPolicyURL: "https://www.ubuntu.com/legal/terms-and-policies/privacy-policy",
   385  			},
   386  		},
   387  
   388  		{
   389  			fixture: "test-fixtures/debian-8",
   390  
   391  			release: &Release{
   392  				PrettyName:   "Debian GNU/Linux 8 (jessie)",
   393  				Name:         "Debian GNU/Linux",
   394  				ID:           "debian",
   395  				IDLike:       nil,
   396  				Version:      "8 (jessie)",
   397  				VersionID:    "8",
   398  				HomeURL:      "http://www.debian.org/",
   399  				SupportURL:   "http://www.debian.org/support",
   400  				BugReportURL: "https://bugs.debian.org/",
   401  			},
   402  		},
   403  
   404  		{
   405  			fixture: "test-fixtures/centos-8",
   406  
   407  			release: &Release{
   408  				PrettyName: "CentOS Linux 8 (Core)",
   409  				Name:       "CentOS Linux",
   410  				ID:         "centos",
   411  				IDLike: []string{
   412  					"rhel",
   413  					"fedora",
   414  				},
   415  				Version:      "8 (Core)",
   416  				VersionID:    "8",
   417  				HomeURL:      "https://www.centos.org/",
   418  				BugReportURL: "https://bugs.centos.org/",
   419  				CPEName:      "cpe:/o:centos:centos:8",
   420  			},
   421  		},
   422  
   423  		{
   424  			fixture: "test-fixtures/rhel-8",
   425  
   426  			release: &Release{
   427  				PrettyName:   "Red Hat Enterprise Linux 8.1 (Ootpa)",
   428  				Name:         "Red Hat Enterprise Linux",
   429  				ID:           "rhel",
   430  				IDLike:       []string{"fedora"},
   431  				Version:      "8.1 (Ootpa)",
   432  				VersionID:    "8.1",
   433  				HomeURL:      "https://www.redhat.com/",
   434  				BugReportURL: "https://bugzilla.redhat.com/",
   435  				CPEName:      "cpe:/o:redhat:enterprise_linux:8.1:GA",
   436  			},
   437  		},
   438  
   439  		{
   440  			fixture: "test-fixtures/unprintable",
   441  
   442  			release: &Release{
   443  				PrettyName:   "Debian GNU/Linux 8 (jessie)",
   444  				Name:         "Debian GNU/Linux",
   445  				ID:           "debian",
   446  				IDLike:       nil,
   447  				Version:      "8 (jessie)",
   448  				VersionID:    "8",
   449  				HomeURL:      "http://www.debian.org/",
   450  				SupportURL:   "http://www.debian.org/support",
   451  				BugReportURL: "https://bugs.debian.org/",
   452  			},
   453  		},
   454  	}
   455  
   456  	for _, test := range tests {
   457  		t.Run(test.fixture,
   458  			func(t *testing.T) {
   459  				release,
   460  					err := parseOsRelease(retrieveFixtureContentsAsString(test.fixture,
   461  					t))
   462  				require.NoError(t,
   463  					err)
   464  				assert.Equal(t,
   465  					test.release,
   466  					release)
   467  			})
   468  	}
   469  
   470  }
   471  
   472  func TestParseSystemReleaseCPE(t *testing.T) {
   473  	tests := []struct {
   474  		fixture string
   475  		release *Release
   476  	}{
   477  		{
   478  			fixture: "test-fixtures/os/centos6/etc/system-release-cpe",
   479  			release: &Release{
   480  				PrettyName: "centos",
   481  				Name:       "centos",
   482  				ID:         "centos",
   483  				IDLike:     []string{"centos"},
   484  				Version:    "6",
   485  				VersionID:  "6",
   486  				CPEName:    "cpe:/o:centos:linux:6:GA",
   487  			},
   488  		},
   489  		{
   490  			fixture: "test-fixtures/bad-system-release-cpe",
   491  			release: nil,
   492  		},
   493  	}
   494  
   495  	for _, test := range tests {
   496  		t.Run(test.fixture, func(t *testing.T) {
   497  			contents := retrieveFixtureContentsAsString(test.fixture, t)
   498  			release, err := parseSystemReleaseCPE(contents)
   499  			require.NoError(t, err)
   500  			if test.release == nil {
   501  				assert.Nil(t, release)
   502  				return
   503  			}
   504  
   505  			assert.Equal(t, test.release, release)
   506  		})
   507  	}
   508  }
   509  
   510  func TestParseRedhatRelease(t *testing.T) {
   511  	tests := []struct {
   512  		fixture string
   513  		name    string
   514  		release *Release
   515  	}{
   516  		{
   517  			fixture: "test-fixtures/os/centos5/etc/redhat-release",
   518  			name:    "Centos 5",
   519  			release: &Release{
   520  				PrettyName: "CentOS release 5.7 (Final)",
   521  				Name:       "CentOS",
   522  				ID:         "centos",
   523  				IDLike:     []string{"centos"},
   524  				Version:    "5.7",
   525  				VersionID:  "5.7",
   526  			},
   527  		},
   528  		{
   529  			fixture: "test-fixtures/bad-redhat-release",
   530  			name:    "Centos 5 Bad Redhat Release",
   531  			release: nil,
   532  		},
   533  	}
   534  
   535  	for _, test := range tests {
   536  		t.Run(test.name, func(t *testing.T) {
   537  			release, err := parseRedhatRelease(retrieveFixtureContentsAsString(test.fixture, t))
   538  			require.NoError(t, err)
   539  			if test.release == nil {
   540  				assert.Nil(t, release)
   541  				return
   542  			}
   543  
   544  			assert.Equal(t, test.release, release)
   545  		})
   546  	}
   547  }
   548  
   549  func retrieveFixtureContentsAsString(fixturePath string, t *testing.T) string {
   550  	fixture, err := os.Open(fixturePath)
   551  	if err != nil {
   552  		t.Fatalf("could not open test fixture=%s: %+v", fixturePath, err)
   553  	}
   554  	defer fixture.Close()
   555  
   556  	b, err := io.ReadAll(fixture)
   557  	if err != nil {
   558  		t.Fatalf("unable to read fixture file: %+v", err)
   559  	}
   560  
   561  	return string(b)
   562  }