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  }