github.com/anchore/syft@v1.38.2/syft/pkg/cataloger/redhat/parse_rpm_archive_test.go (about)

     1  package redhat
     2  
     3  import (
     4  	"context"
     5  	"encoding/hex"
     6  	"testing"
     7  
     8  	"github.com/google/go-cmp/cmp"
     9  	"github.com/google/go-cmp/cmp/cmpopts"
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  
    13  	"github.com/anchore/syft/syft/file"
    14  	"github.com/anchore/syft/syft/pkg"
    15  	"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
    16  )
    17  
    18  func TestParseRpmFiles(t *testing.T) {
    19  	ctx := context.TODO()
    20  	abcRpmLocation := file.NewLocation("abc-1.01-9.hg20160905.el7.x86_64.rpm")
    21  	zorkRpmLocation := file.NewLocation("zork-1.0.3-1.el7.x86_64.rpm")
    22  	tests := []struct {
    23  		name         string
    24  		fixtureDir   string
    25  		fixtureImage string
    26  		skipFiles    bool
    27  		expected     []pkg.Package
    28  	}{
    29  		{
    30  			name:       "go case",
    31  			fixtureDir: "test-fixtures/rpms",
    32  			expected: []pkg.Package{
    33  				{
    34  					Name:      "abc",
    35  					Version:   "0:1.01-9.hg20160905.el7",
    36  					PURL:      "pkg:rpm/abc@1.01-9.hg20160905.el7?arch=x86_64&epoch=0&upstream=abc-1.01-9.hg20160905.el7.src.rpm",
    37  					Locations: file.NewLocationSet(file.NewLocation("abc-1.01-9.hg20160905.el7.x86_64.rpm")),
    38  					FoundBy:   "rpm-archive-cataloger",
    39  					Type:      pkg.RpmPkg,
    40  					Licenses: pkg.NewLicenseSet(
    41  						pkg.NewLicenseFromLocationsWithContext(ctx, "MIT", abcRpmLocation),
    42  					),
    43  					Metadata: pkg.RpmArchive{
    44  						Name:      "abc",
    45  						Epoch:     intRef(0),
    46  						Arch:      "x86_64",
    47  						Release:   "9.hg20160905.el7",
    48  						Version:   "1.01",
    49  						SourceRpm: "abc-1.01-9.hg20160905.el7.src.rpm",
    50  						Signatures: []pkg.RpmSignature{
    51  							{
    52  								PublicKeyAlgorithm: "RSA",
    53  								HashAlgorithm:      "SHA256",
    54  								Created:            "Wed Sep 21 07:09:44 2016",
    55  								IssuerKeyID:        "6a2faea2352c64e5",
    56  							},
    57  						},
    58  						Size:   17396,
    59  						Vendor: "Fedora Project",
    60  						Files: []pkg.RpmFileRecord{
    61  							{"/usr/bin/abc", 33261, 7120, file.Digest{"sha256", "8f8495a65c66762b60afa0c3949d81b275ca6fa0601696caba5af762f455d0b9"}, "root", "root", ""},
    62  							{"/usr/share/doc/abc-1.01", 16877, 4096, file.Digest{}, "root", "root", ""},
    63  							{"/usr/share/doc/abc-1.01/readme.md", 33188, 4984, file.Digest{"sha256", "808af8a28391e96ca0d91086789488dda3724fe7c8b2859efd464fb04b94b2d4"}, "root", "root", "d"},
    64  							{"/usr/share/doc/abc-1.01/readmeaig", 33188, 3324, file.Digest{"sha256", "530ec6175cf7fbeb7b595cbe7a50994429c4e62cae6666fb3a1d5745f3127b19"}, "root", "root", "d"},
    65  							{"/usr/share/man/man1/abc.1.gz", 33188, 1968, file.Digest{"sha256", "cf2cfe25b29087e60ffd5f31f974a0762172fc2f009704951f12ff750ea77ed6"}, "root", "root", "d"},
    66  						},
    67  					},
    68  				},
    69  				{
    70  					Name:      "zork",
    71  					Version:   "0:1.0.3-1.el7",
    72  					PURL:      "pkg:rpm/zork@1.0.3-1.el7?arch=x86_64&epoch=0&upstream=zork-1.0.3-1.el7.src.rpm",
    73  					Locations: file.NewLocationSet(zorkRpmLocation),
    74  					FoundBy:   "rpm-archive-cataloger",
    75  					Type:      pkg.RpmPkg,
    76  					Licenses: pkg.NewLicenseSet(
    77  						pkg.NewLicenseFromLocationsWithContext(ctx, "Public Domain", zorkRpmLocation),
    78  					),
    79  					Metadata: pkg.RpmArchive{
    80  						Name:      "zork",
    81  						Epoch:     intRef(0),
    82  						Arch:      "x86_64",
    83  						Release:   "1.el7",
    84  						Version:   "1.0.3",
    85  						SourceRpm: "zork-1.0.3-1.el7.src.rpm",
    86  						Size:      262367,
    87  						Signatures: []pkg.RpmSignature{
    88  							{
    89  								PublicKeyAlgorithm: "RSA",
    90  								HashAlgorithm:      "SHA256",
    91  								Created:            "Tue Mar  2 17:32:21 2021",
    92  								IssuerKeyID:        "6a2faea2352c64e5",
    93  							},
    94  						},
    95  						Vendor: "Fedora Project",
    96  						Files: []pkg.RpmFileRecord{
    97  							{"/usr/bin/zork", 33261, 115440, file.Digest{"sha256", "31b2ffc20b676a8fff795a45308f584273b9c47e8f7e196b4f36220b2734b472"}, "root", "root", ""},
    98  							{"/usr/share/doc/zork-1.0.3", 16877, 38, file.Digest{}, "root", "root", ""},
    99  							{"/usr/share/doc/zork-1.0.3/README.md", 33188, 5123, file.Digest{"sha256", "0013d67610a80c9f62d151a952f18d520b15b4c505b3ec2af34b96ab824654a4"}, "root", "root", "d"},
   100  							{"/usr/share/doc/zork-1.0.3/history", 33188, 4816, file.Digest{"sha256", "6949044a65adefca6ac0132c18cfccc4ba8fdaec948424b6ccb60afd8a6ac82f"}, "root", "root", "d"},
   101  							{"/usr/share/licenses/zork-1.0.3", 16877, 24, file.Digest{}, "root", "root", ""},
   102  							{"/usr/share/licenses/zork-1.0.3/readme.txt", 33188, 146, file.Digest{"sha256", "9d6f7500555a2ecc3cb289dcca1e37fb96894dab1e4ba692b4d36fd6c3bdf939"}, "root", "root", "l"},
   103  							{"/usr/share/man/man6/dungeon.6.gz", 33188, 3800, file.Digest{"sha256", "9b065d6a6f65b4d2d038fcca0af47a38e8723c32008d08659739ac34abe018da"}, "root", "root", "d"},
   104  							{"/usr/share/man/man6/zork.6.gz", 33188, 34, file.Digest{"sha256", "18fbcb598bc40a25befe26256e29366984d2288dd154f877b8ac5fc138dd0884"}, "root", "root", "d"},
   105  							{"/usr/share/zork/dtextc.dat", 33188, 133008, file.Digest{"sha256", "25ca42857c2b32054916d9258152293ead644023d5e03bec039ea92014e2ef91"}, "root", "root", ""},
   106  						},
   107  					},
   108  				},
   109  			},
   110  		},
   111  		{
   112  			name:       "bad rpms",
   113  			fixtureDir: "test-fixtures/bad",
   114  		},
   115  		{
   116  			name:         "rpms with signatures from RSA header",
   117  			fixtureImage: "image-rpm-archive",
   118  			skipFiles:    true,
   119  			expected: []pkg.Package{
   120  				{
   121  					Name:      "postgresql14-server",
   122  					Version:   "0:14.10-1PGDG.rhel9",
   123  					PURL:      "pkg:rpm/postgresql14-server@14.10-1PGDG.rhel9?arch=x86_64&epoch=0&upstream=postgresql14-14.10-1PGDG.rhel9.src.rpm",
   124  					Locations: file.NewLocationSet(file.NewLocation("/postgresql14-server-14.10-1PGDG.rhel9.x86_64.rpm")),
   125  					FoundBy:   "rpm-archive-cataloger",
   126  					Type:      pkg.RpmPkg,
   127  					Licenses:  pkg.NewLicenseSet(pkg.NewLicenseFromLocations("PostgreSQL", file.NewLocation("/postgresql14-server-14.10-1PGDG.rhel9.x86_64.rpm"))),
   128  					Language:  "",
   129  					CPEs:      nil,
   130  					Metadata: pkg.RpmArchive{
   131  						Name:      "postgresql14-server",
   132  						Version:   "14.10",
   133  						Epoch:     ref(0),
   134  						Arch:      "x86_64",
   135  						Release:   "1PGDG.rhel9",
   136  						SourceRpm: "postgresql14-14.10-1PGDG.rhel9.src.rpm",
   137  						Size:      24521699,
   138  						Signatures: []pkg.RpmSignature{
   139  							{
   140  								PublicKeyAlgorithm: "RSA",
   141  								HashAlgorithm:      "SHA256",
   142  								Created:            "Tue Jan  2 16:45:56 2024",
   143  								IssuerKeyID:        "40bca2b408b40d20",
   144  							},
   145  						},
   146  						Vendor: "PostgreSQL Global Development Group",
   147  						// note: files are not asserted in this test
   148  					},
   149  				},
   150  			},
   151  		},
   152  	}
   153  
   154  	for _, test := range tests {
   155  		t.Run(test.name, func(t *testing.T) {
   156  			var opts []cmp.Option
   157  			if test.skipFiles {
   158  				opts = append(opts, cmpopts.IgnoreFields(pkg.RpmArchive{}, "Files"))
   159  			}
   160  			pkgtest.NewCatalogTester().
   161  				WithCompareOptions(opts...).
   162  				FromDirectory(t, test.fixtureDir).
   163  				WithImageResolver(t, test.fixtureImage).
   164  				IgnoreLocationLayer().
   165  				Expects(test.expected, nil).
   166  				TestCataloger(t, NewArchiveCataloger())
   167  		})
   168  	}
   169  }
   170  
   171  func Test_parseRSA(t *testing.T) {
   172  	tests := []struct {
   173  		name    string
   174  		data    string
   175  		want    *pkg.RpmSignature
   176  		wantErr assert.ErrorAssertionFunc
   177  	}{
   178  		{
   179  			name: "older RSA header",
   180  			data: "89021503050058d3e39b0946fca2c105b9de0102b12a1000a2b3d347b51142e83b2de5e03ba9096f6330b72c140e46200d662b01c78534d14fab2ad4f07325119386830dd590219f27a22e420680283c500c40e6fba95404884b0a0abca8f198030ddc03653b7db2883b8230687e9e73d43eb5a24dbabfa48bbb3d1151ed264744e5e8ca169b0c4673a1440a9b99e53e693c9722f6423833cd7795e3044227fb922e21b7c007f03e923fae3f04d1ac2e8581e68c6790115b6dccfc02c8cb41681ed84785df086d6e26008c257d088a524ba2e7a7a5f41ad26b106c67b87fe48118b69662db612c23d2140059286f1ba7764627def6867ad0e11fe3a01fb1422dabe6f5cdf4cd876dc4fadfd2364bc3ba3758db94aaf3b82368cba65cf762287f713eb7ddc773acf93b083c739577a7eaf1f99e7dcbb8db1da050490e9fb67c838448db060a9e619d318c96f03e4363808d84ce29e8c102c290cc2bfab5746f3d9ddc9eb8b428f3ad2678abb2d46e846ddca7fc41322d76a97be6d416b4750f23320ec725e082be4496483b4cd3a3d2c515b3c8a6e27541139d809245140303877b84842ed2dd0454a78b2dfb7d6213784697077a8167942ebda5995a28d8256957e33e301706c35944ae05c7a54a4dd89be654d26cefa5cf0f616bbeaf317138371b09c5bbd5531f716020e553354ce5dbce3d9bb72f21e1857408dfd5a35250ff40f61ae1e25409ae9d21db76b8878341f4762a22be2189",
   181  			// RSA/SHA1, Thu Mar 23 15:02:51 2017, Key ID 0946fca2c105b9de
   182  			want: &pkg.RpmSignature{
   183  				PublicKeyAlgorithm: "RSA",
   184  				HashAlgorithm:      "SHA1",
   185  				Created:            "Thu Mar 23 15:02:51 2017",
   186  				IssuerKeyID:        "0946fca2c105b9de",
   187  			},
   188  		},
   189  		{
   190  			name: "newer RSA header",
   191  			data: "89024a04000108003416210421cb256ae16fc54c6e652949702d426d350d275d050262804369161c72656c656e6740726f636b796c696e75782e6f7267000a0910702d426d350d275dc8910ffd14f0f80297481fea648e7ba5a74bce10c5faccc2bbe588caece04be34d304a6a445538afc97a7033d43c983d27cc8f5ee515b2dd92f3e03354c413e55372a4d19386eb0f2354f9a26ee5fc2e56dfda49555e4a58b49279b70cd2036b04f28125f85942f640f2984e29e079f26bf6f76831d83d95983aa084a3e7b6327be2e23d0d799c4b4d1cfb36147ddfb782bf9df7b331d97f4f46b38f968b6130d87b0ef6bb0d424390fe34e38092babed37440569a93f55f50a2bdb58be0259f35badf7e728bd49824ed47f69fa53b6e26736bde4d8358d959b090e88054c3e179745dc7377e41b54b4e10223f4859e88162c7c5ec64b78d36cf8a914c1c2deb8c4f19a70d406e70756a89195d6aee488a9b40b9dbb76b2c38e528eb88d08ec35774a48ed9ce4e0dfac45cb7613ad5921f54c61d3aae5d7b3ab0e2e6ff867ac8f395b37af78b5c01022a4a4e62f7a99425fccb7439880cd6b393a3050b2e9512693bc36f6fe9de2921dda59710a1508965065244cf9f0f8cfc5bd554777f1a84d2249339234d62f2441249f617ad7df4fb01367a91d3a880e86fdb84bc6d03a127b44a28c6ceadef89e438db9640aa59b8a3f460b07272511f8187a5f3b163c8fd1caa61667401bce2ccdb1c176c46be10ef8033903132cca5889fa3661b2fba590c41fa1c104c08426677bdbf745a52ccd28f581960cf9d7e4ede3b9584aacb2f20ef93",
   192  			// RSA/SHA256, Sun May 15 00:03:53 2022, Key ID 702d426d350d275d
   193  			want: &pkg.RpmSignature{
   194  				PublicKeyAlgorithm: "RSA",
   195  				HashAlgorithm:      "SHA256",
   196  				Created:            "Sun May 15 00:03:53 2022",
   197  				IssuerKeyID:        "702d426d350d275d",
   198  			},
   199  		},
   200  		{
   201  			name: "example from rocky9",
   202  			data: "8901b304000108001d162104d4bf08ae67a0b4c7a1dbccd240bca2b408b40d20050265943dc4000a091040bca2b408b40d203b270bff71678ffeb190833a19a82112f59eee64cba186ab454d4526e0b3c8797e723f6916daff1b1f18cbf53c0da5d398a3a42065e79e5ca939f721652f38400dd4cac1107a902b1dae880649437ad0242444f3f07115172cae0a207b7cf8340af2f4a94976325f1dc165d5c2a564be322c4e130adb6217e7138b689f08898c407b223aa1ff8f8d592f31eba2256c02fae70ce4022d688a487972646b8bf1b518b5d6549c1e60fd812134422d9fdb41cf799f5eab80e48b4ab7cff84362dc867ed1af1416dd78e92bcc59217de7064b9a015d94a5097788689b9b6fbdeea679cfe4a6947f73dc3a6c810f2cb999d279b01564422d1500fc1bd8bd1eefa2d60660127ffef24067354660f93c0faf81f4edd599dd7e4b77fe4bff6c7a0ea83530c817c38d1f2364175883c6ef7b6dec86ad282bdd5138b8597567db96810c4ed6454a4ab1d98f0425dcd8892a5d46ed9289cb3ae3e1f1e2663d3e8188e873428f6cf7163563ed3860edc4fee81522389508847e692e2d13310eb4b40f7fdd7eb364a0b2dc",
   203  			// RSA/SHA256, Tue Jan  2 16:45:56 2024, Key ID 40bca2b408b40d20
   204  			want: &pkg.RpmSignature{
   205  				PublicKeyAlgorithm: "RSA",
   206  				HashAlgorithm:      "SHA256",
   207  				Created:            "Tue Jan  2 16:45:56 2024",
   208  				IssuerKeyID:        "40bca2b408b40d20",
   209  			},
   210  		},
   211  	}
   212  	for _, tt := range tests {
   213  		t.Run(tt.name, func(t *testing.T) {
   214  			if tt.wantErr == nil {
   215  				tt.wantErr = assert.NoError
   216  			}
   217  
   218  			data, err := hex.DecodeString(tt.data)
   219  			require.NoError(t, err)
   220  
   221  			got, err := parsePGP(data)
   222  			if !tt.wantErr(t, err) {
   223  				return
   224  			}
   225  			assert.Equal(t, tt.want, got)
   226  		})
   227  	}
   228  }
   229  
   230  func ref[T any](v T) *T {
   231  	return &v
   232  }
   233  
   234  func Test_corruptRpmArchive(t *testing.T) {
   235  	pkgtest.NewCatalogTester().
   236  		FromFile(t, "test-fixtures/bad/bad.rpm").
   237  		WithError().
   238  		TestParser(t, parseRpmArchive)
   239  }