Upgrade generic cataloger (#1281)

* add second generation of generic cataloger

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* upgrade aplm cataloger to use generic.Cataloger

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* remove pacakge found-by attribute from the definition of a package ID

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
Alex Goodman 2022-10-24 11:12:12 -04:00 committed by GitHub
parent 7a8b96abc2
commit b44f441c82
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
40 changed files with 495 additions and 245 deletions

View file

@ -1,10 +1,10 @@
{
"bomFormat": "CycloneDX",
"specVersion": "1.4",
"serialNumber": "urn:uuid:3ea3363f-3945-4859-9ba1-9a395983d248",
"serialNumber": "urn:uuid:f426926b-4867-4b52-9142-23997f685f2c",
"version": 1,
"metadata": {
"timestamp": "2022-05-23T12:05:00-07:00",
"timestamp": "2022-10-24T09:54:37-04:00",
"tools": [
{
"vendor": "anchore",
@ -20,7 +20,7 @@
},
"components": [
{
"bom-ref": "b85dbb4e6ece5082",
"bom-ref": "e624319940d8d36a",
"type": "library",
"name": "package-1",
"version": "1.0.1",
@ -57,7 +57,7 @@
]
},
{
"bom-ref": "pkg:deb/debian/package-2@2.0.1?package-id=ceda99598967ae8d",
"bom-ref": "pkg:deb/debian/package-2@2.0.1?package-id=b8645f4ac2a0891e",
"type": "library",
"name": "package-2",
"version": "2.0.1",

View file

@ -1,10 +1,10 @@
{
"bomFormat": "CycloneDX",
"specVersion": "1.4",
"serialNumber": "urn:uuid:c825402b-bbfa-4ad5-81b1-6a8332a6a8b6",
"serialNumber": "urn:uuid:41bbbcc7-694d-4b07-a678-0afb67dabdf9",
"version": 1,
"metadata": {
"timestamp": "2022-05-23T12:05:01-07:00",
"timestamp": "2022-10-24T09:54:37-04:00",
"tools": [
{
"vendor": "anchore",
@ -13,7 +13,7 @@
}
],
"component": {
"bom-ref": "e779c1ed804ba529",
"bom-ref": "522dc6b135a55bb4",
"type": "container",
"name": "user-image-input",
"version": "sha256:2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368"
@ -21,7 +21,7 @@
},
"components": [
{
"bom-ref": "2a46171f91c8d4bc",
"bom-ref": "5ffee24fb164cffc",
"type": "library",
"name": "package-1",
"version": "1.0.1",
@ -53,7 +53,7 @@
},
{
"name": "syft:location:0:layerID",
"value": "sha256:cd8f3884f1211d65c19ce5bbc5174bcd2ce8ba96b63e5b3693969a53279c4405"
"value": "sha256:fb6beecb75b39f4bb813dbf177e501edd5ddb3e69bb45cedeb78c676ee1b7a59"
},
{
"name": "syft:location:0:path",
@ -62,7 +62,7 @@
]
},
{
"bom-ref": "pkg:deb/debian/package-2@2.0.1?package-id=ae77680e9b1d087e",
"bom-ref": "pkg:deb/debian/package-2@2.0.1?package-id=8b16570b2b4155c3",
"type": "library",
"name": "package-2",
"version": "2.0.1",
@ -83,7 +83,7 @@
},
{
"name": "syft:location:0:layerID",
"value": "sha256:42d2ea51c688e6dc7be81a305acbe006d27a6ef0c26ae3888fd0d4ce44f69265"
"value": "sha256:319b588ce64253a87b533c8ed01cf0025e0eac98e7b516e12532957e1244fdec"
},
{
"name": "syft:location:0:path",

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:a259c072-aaaf-4a3f-a707-49f691b1e9d9" version="1">
<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:19df9583-d8b7-4683-81a6-e57cc8841321" version="1">
<metadata>
<timestamp>2022-05-23T12:02:41-07:00</timestamp>
<timestamp>2022-10-24T09:54:54-04:00</timestamp>
<tools>
<tool>
<vendor>anchore</vendor>
@ -14,7 +14,7 @@
</component>
</metadata>
<components>
<component bom-ref="b85dbb4e6ece5082" type="library">
<component bom-ref="e624319940d8d36a" type="library">
<name>package-1</name>
<version>1.0.1</version>
<licenses>
@ -32,7 +32,7 @@
<property name="syft:location:0:path">/some/path/pkg1</property>
</properties>
</component>
<component bom-ref="pkg:deb/debian/package-2@2.0.1?package-id=ceda99598967ae8d" type="library">
<component bom-ref="pkg:deb/debian/package-2@2.0.1?package-id=b8645f4ac2a0891e" type="library">
<name>package-2</name>
<version>2.0.1</version>
<cpe>cpe:2.3:*:some:package:2:*:*:*:*:*:*:*</cpe>

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:155802bd-09e5-4b95-9485-826b94447495" version="1">
<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:5342511c-3580-4cae-b373-20bbf14ba7a3" version="1">
<metadata>
<timestamp>2022-05-23T12:02:42-07:00</timestamp>
<timestamp>2022-10-24T09:54:54-04:00</timestamp>
<tools>
<tool>
<vendor>anchore</vendor>
@ -9,13 +9,13 @@
<version>v0.42.0-bogus</version>
</tool>
</tools>
<component bom-ref="e779c1ed804ba529" type="container">
<component bom-ref="522dc6b135a55bb4" type="container">
<name>user-image-input</name>
<version>sha256:2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368</version>
</component>
</metadata>
<components>
<component bom-ref="2a46171f91c8d4bc" type="library">
<component bom-ref="5ffee24fb164cffc" type="library">
<name>package-1</name>
<version>1.0.1</version>
<licenses>
@ -30,11 +30,11 @@
<property name="syft:package:language">python</property>
<property name="syft:package:metadataType">PythonPackageMetadata</property>
<property name="syft:package:type">python</property>
<property name="syft:location:0:layerID">sha256:cd8f3884f1211d65c19ce5bbc5174bcd2ce8ba96b63e5b3693969a53279c4405</property>
<property name="syft:location:0:layerID">sha256:fb6beecb75b39f4bb813dbf177e501edd5ddb3e69bb45cedeb78c676ee1b7a59</property>
<property name="syft:location:0:path">/somefile-1.txt</property>
</properties>
</component>
<component bom-ref="pkg:deb/debian/package-2@2.0.1?package-id=ae77680e9b1d087e" type="library">
<component bom-ref="pkg:deb/debian/package-2@2.0.1?package-id=8b16570b2b4155c3" type="library">
<name>package-2</name>
<version>2.0.1</version>
<cpe>cpe:2.3:*:some:package:2:*:*:*:*:*:*:*</cpe>
@ -43,7 +43,7 @@
<property name="syft:package:foundBy">the-cataloger-2</property>
<property name="syft:package:metadataType">DpkgMetadata</property>
<property name="syft:package:type">deb</property>
<property name="syft:location:0:layerID">sha256:42d2ea51c688e6dc7be81a305acbe006d27a6ef0c26ae3888fd0d4ce44f69265</property>
<property name="syft:location:0:layerID">sha256:319b588ce64253a87b533c8ed01cf0025e0eac98e7b516e12532957e1244fdec</property>
<property name="syft:location:0:path">/somefile-2.txt</property>
<property name="syft:metadata:installedSize">0</property>
</properties>

View file

@ -3,18 +3,18 @@
"name": "/some/path",
"spdxVersion": "SPDX-2.2",
"creationInfo": {
"created": "2022-05-23T19:10:22.25645Z",
"created": "2022-10-24T13:54:19.225779Z",
"creators": [
"Organization: Anchore, Inc",
"Tool: syft-v0.42.0-bogus"
],
"licenseListVersion": "3.17"
"licenseListVersion": "3.18"
},
"dataLicense": "CC0-1.0",
"documentNamespace": "https://anchore.com/syft/dir/some/path-81dbcbfa-251d-4ad5-9b01-be91afb16469",
"documentNamespace": "https://anchore.com/syft/dir/some/path-cd89c782-240b-461e-81a1-63863e02642f",
"packages": [
{
"SPDXID": "SPDXRef-b85dbb4e6ece5082",
"SPDXID": "SPDXRef-e624319940d8d36a",
"name": "package-1",
"licenseConcluded": "MIT",
"downloadLocation": "NOASSERTION",
@ -36,7 +36,7 @@
"versionInfo": "1.0.1"
},
{
"SPDXID": "SPDXRef-ceda99598967ae8d",
"SPDXID": "SPDXRef-b8645f4ac2a0891e",
"name": "package-2",
"licenseConcluded": "NONE",
"downloadLocation": "NOASSERTION",

View file

@ -3,18 +3,18 @@
"name": "user-image-input",
"spdxVersion": "SPDX-2.2",
"creationInfo": {
"created": "2022-05-23T19:10:22.412847Z",
"created": "2022-10-24T13:54:19.477217Z",
"creators": [
"Organization: Anchore, Inc",
"Tool: syft-v0.42.0-bogus"
],
"licenseListVersion": "3.17"
"licenseListVersion": "3.18"
},
"dataLicense": "CC0-1.0",
"documentNamespace": "https://anchore.com/syft/image/user-image-input-c9945597-78ce-4e9b-89d2-68b8e4e4ccb9",
"documentNamespace": "https://anchore.com/syft/image/user-image-input-0b40ce75-7e54-4760-bd9d-4fa833b352dd",
"packages": [
{
"SPDXID": "SPDXRef-2a46171f91c8d4bc",
"SPDXID": "SPDXRef-5ffee24fb164cffc",
"name": "package-1",
"licenseConcluded": "MIT",
"downloadLocation": "NOASSERTION",
@ -36,7 +36,7 @@
"versionInfo": "1.0.1"
},
{
"SPDXID": "SPDXRef-ae77680e9b1d087e",
"SPDXID": "SPDXRef-8b16570b2b4155c3",
"name": "package-2",
"licenseConcluded": "NONE",
"downloadLocation": "NOASSERTION",

View file

@ -3,7 +3,7 @@
"name": "user-image-input",
"spdxVersion": "SPDX-2.2",
"creationInfo": {
"created": "2022-09-19T18:39:05.841331Z",
"created": "2022-10-24T13:54:19.48428Z",
"creators": [
"Organization: Anchore, Inc",
"Tool: syft-v0.42.0-bogus"
@ -11,10 +11,10 @@
"licenseListVersion": "3.18"
},
"dataLicense": "CC0-1.0",
"documentNamespace": "https://anchore.com/syft/image/user-image-input-6cf0595e-7d69-4990-aef5-8183b52023b9",
"documentNamespace": "https://anchore.com/syft/image/user-image-input-1a4dc179-1222-463c-b4e9-619131af7e97",
"packages": [
{
"SPDXID": "SPDXRef-2a46171f91c8d4bc",
"SPDXID": "SPDXRef-5ffee24fb164cffc",
"name": "package-1",
"licenseConcluded": "MIT",
"downloadLocation": "NOASSERTION",
@ -44,7 +44,7 @@
"versionInfo": "1.0.1"
},
{
"SPDXID": "SPDXRef-ae77680e9b1d087e",
"SPDXID": "SPDXRef-8b16570b2b4155c3",
"name": "package-2",
"licenseConcluded": "NONE",
"downloadLocation": "NOASSERTION",
@ -118,32 +118,32 @@
],
"relationships": [
{
"spdxElementId": "SPDXRef-2a46171f91c8d4bc",
"spdxElementId": "SPDXRef-5ffee24fb164cffc",
"relationshipType": "CONTAINS",
"relatedSpdxElement": "SPDXRef-5265a4dde3edbf7c"
},
{
"spdxElementId": "SPDXRef-2a46171f91c8d4bc",
"spdxElementId": "SPDXRef-5ffee24fb164cffc",
"relationshipType": "CONTAINS",
"relatedSpdxElement": "SPDXRef-839d99ee67d9d174"
},
{
"spdxElementId": "SPDXRef-2a46171f91c8d4bc",
"spdxElementId": "SPDXRef-5ffee24fb164cffc",
"relationshipType": "CONTAINS",
"relatedSpdxElement": "SPDXRef-9c2f7510199b17f6"
},
{
"spdxElementId": "SPDXRef-2a46171f91c8d4bc",
"spdxElementId": "SPDXRef-5ffee24fb164cffc",
"relationshipType": "CONTAINS",
"relatedSpdxElement": "SPDXRef-c641caa71518099f"
},
{
"spdxElementId": "SPDXRef-2a46171f91c8d4bc",
"spdxElementId": "SPDXRef-5ffee24fb164cffc",
"relationshipType": "CONTAINS",
"relatedSpdxElement": "SPDXRef-c6f5b29dca12661f"
},
{
"spdxElementId": "SPDXRef-2a46171f91c8d4bc",
"spdxElementId": "SPDXRef-5ffee24fb164cffc",
"relationshipType": "CONTAINS",
"relatedSpdxElement": "SPDXRef-f9e49132a4b96ccd"
}

View file

@ -2,16 +2,16 @@ SPDXVersion: SPDX-2.2
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: .
DocumentNamespace: https://anchore.com/syft/dir/bdb67358-651c-4dd8-b5ee-5318936eb16a
LicenseListVersion: 3.17
DocumentNamespace: https://anchore.com/syft/dir/4593d944-756e-49aa-af4e-b1a5acf09b97
LicenseListVersion: 3.18
Creator: Organization: Anchore, Inc
Creator: Tool: syft-v0.42.0-bogus
Created: 2022-06-07T19:33:39Z
Created: 2022-10-24T13:53:53Z
##### Package: @at-sign
PackageName: @at-sign
SPDXID: SPDXRef-Package---at-sign-739e4f0d93fb8298
SPDXID: SPDXRef-Package---at-sign-fe69bc18c2698fc4
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageLicenseConcluded: NONE
@ -21,7 +21,7 @@ PackageCopyrightText: NOASSERTION
##### Package: some/slashes
PackageName: some/slashes
SPDXID: SPDXRef-Package--some-slashes-26db06648b24bff9
SPDXID: SPDXRef-Package--some-slashes-57ed206c09e6e5f4
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageLicenseConcluded: NONE
@ -31,7 +31,7 @@ PackageCopyrightText: NOASSERTION
##### Package: under_scores
PackageName: under_scores
SPDXID: SPDXRef-Package--under-scores-250cbfefcdea318b
SPDXID: SPDXRef-Package--under-scores-8b7505907fdaf19d
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageLicenseConcluded: NONE

View file

@ -2,16 +2,16 @@ SPDXVersion: SPDX-2.2
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: /some/path
DocumentNamespace: https://anchore.com/syft/dir/some/path-c6b20d03-1478-4513-9feb-1ec427d4b547
LicenseListVersion: 3.17
DocumentNamespace: https://anchore.com/syft/dir/some/path-a4e58523-00d0-4135-9d21-cf586fbd340c
LicenseListVersion: 3.18
Creator: Organization: Anchore, Inc
Creator: Tool: syft-v0.42.0-bogus
Created: 2022-05-24T22:51:02Z
Created: 2022-10-24T13:53:52Z
##### Package: package-2
PackageName: package-2
SPDXID: SPDXRef-Package-deb-package-2-ceda99598967ae8d
SPDXID: SPDXRef-Package-deb-package-2-b8645f4ac2a0891e
PackageVersion: 2.0.1
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
@ -24,7 +24,7 @@ ExternalRef: PACKAGE_MANAGER purl pkg:deb/debian/package-2@2.0.1
##### Package: package-1
PackageName: package-1
SPDXID: SPDXRef-Package-python-package-1-b85dbb4e6ece5082
SPDXID: SPDXRef-Package-python-package-1-e624319940d8d36a
PackageVersion: 1.0.1
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false

View file

@ -2,16 +2,16 @@ SPDXVersion: SPDX-2.2
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: user-image-input
DocumentNamespace: https://anchore.com/syft/image/user-image-input-12a877bc-fe9b-40ef-aa9c-4d34f108d0d6
LicenseListVersion: 3.17
DocumentNamespace: https://anchore.com/syft/image/user-image-input-639f628a-5f8b-4050-a69e-90c85f0d7837
LicenseListVersion: 3.18
Creator: Organization: Anchore, Inc
Creator: Tool: syft-v0.42.0-bogus
Created: 2022-05-24T22:51:02Z
Created: 2022-10-24T13:53:53Z
##### Package: package-2
PackageName: package-2
SPDXID: SPDXRef-Package-deb-package-2-ae77680e9b1d087e
SPDXID: SPDXRef-Package-deb-package-2-8b16570b2b4155c3
PackageVersion: 2.0.1
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
@ -24,7 +24,7 @@ ExternalRef: PACKAGE_MANAGER purl pkg:deb/debian/package-2@2.0.1
##### Package: package-1
PackageName: package-1
SPDXID: SPDXRef-Package-python-package-1-2a46171f91c8d4bc
SPDXID: SPDXRef-Package-python-package-1-5ffee24fb164cffc
PackageVersion: 1.0.1
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false

View file

@ -1,7 +1,7 @@
{
"artifacts": [
{
"id": "b85dbb4e6ece5082",
"id": "e624319940d8d36a",
"name": "package-1",
"version": "1.0.1",
"type": "python",
@ -36,7 +36,7 @@
}
},
{
"id": "ceda99598967ae8d",
"id": "b8645f4ac2a0891e",
"name": "package-2",
"version": "2.0.1",
"type": "deb",

View file

@ -1,7 +1,7 @@
{
"artifacts": [
{
"id": "b3fa3ee64756b0c6",
"id": "8373dcf05581b932",
"name": "package-1",
"version": "1.0.1",
"type": "python",
@ -31,7 +31,7 @@
}
},
{
"id": "b324f4d9ee5413fe",
"id": "c3d4da40f387eec7",
"name": "package-2",
"version": "2.0.1",
"type": "deb",

View file

@ -1,7 +1,7 @@
{
"artifacts": [
{
"id": "2a46171f91c8d4bc",
"id": "5ffee24fb164cffc",
"name": "package-1",
"version": "1.0.1",
"type": "python",
@ -9,7 +9,7 @@
"locations": [
{
"path": "/somefile-1.txt",
"layerID": "sha256:4965affaf42a7174561882c5fd87e2db6f0b07df532459ba86f98a8bd2af11de"
"layerID": "sha256:fb6beecb75b39f4bb813dbf177e501edd5ddb3e69bb45cedeb78c676ee1b7a59"
}
],
"licenses": [
@ -32,7 +32,7 @@
}
},
{
"id": "ae77680e9b1d087e",
"id": "8b16570b2b4155c3",
"name": "package-2",
"version": "2.0.1",
"type": "deb",
@ -40,7 +40,7 @@
"locations": [
{
"path": "/somefile-2.txt",
"layerID": "sha256:460c3e27be163efe75df048c4d4cf3a22e7e363f02521fa2e82a3bd257a682d4"
"layerID": "sha256:319b588ce64253a87b533c8ed01cf0025e0eac98e7b516e12532957e1244fdec"
}
],
"licenses": [],
@ -64,11 +64,11 @@
],
"artifactRelationships": [],
"source": {
"id": "00afea0209d754683fdfcdd47cfea94ec9f2e81286be444e297a8c776c4accbf",
"id": "1a678f111c8ddc66fd82687bb024e0dd6af61314404937a80e810c0cf317b796",
"type": "image",
"target": {
"userInput": "user-image-input",
"imageID": "sha256:6b1b476e6dc187bb688566606cf7a59d7804d81169967d8c6bb121627b0a387f",
"imageID": "sha256:3c51b06feb0cda8ee62d0e3755ef2a8496a6b71f8a55b245f07f31c4bb813d31",
"manifestDigest": "sha256:2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"tags": [
@ -78,17 +78,17 @@
"layers": [
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"digest": "sha256:4965affaf42a7174561882c5fd87e2db6f0b07df532459ba86f98a8bd2af11de",
"digest": "sha256:fb6beecb75b39f4bb813dbf177e501edd5ddb3e69bb45cedeb78c676ee1b7a59",
"size": 22
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"digest": "sha256:460c3e27be163efe75df048c4d4cf3a22e7e363f02521fa2e82a3bd257a682d4",
"digest": "sha256:319b588ce64253a87b533c8ed01cf0025e0eac98e7b516e12532957e1244fdec",
"size": 16
}
],
"manifest": "eyJzY2hlbWFWZXJzaW9uIjoyLCJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC52Mitqc29uIiwiY29uZmlnIjp7Im1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uL3ZuZC5kb2NrZXIuY29udGFpbmVyLmltYWdlLnYxK2pzb24iLCJzaXplIjo2NzMsImRpZ2VzdCI6InNoYTI1Njo2YjFiNDc2ZTZkYzE4N2JiNjg4NTY2NjA2Y2Y3YTU5ZDc4MDRkODExNjk5NjdkOGM2YmIxMjE2MjdiMGEzODdmIn0sImxheWVycyI6W3sibWVkaWFUeXBlIjoiYXBwbGljYXRpb24vdm5kLmRvY2tlci5pbWFnZS5yb290ZnMuZGlmZi50YXIuZ3ppcCIsInNpemUiOjIwNDgsImRpZ2VzdCI6InNoYTI1Njo0OTY1YWZmYWY0MmE3MTc0NTYxODgyYzVmZDg3ZTJkYjZmMGIwN2RmNTMyNDU5YmE4NmY5OGE4YmQyYWYxMWRlIn0seyJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmltYWdlLnJvb3Rmcy5kaWZmLnRhci5nemlwIiwic2l6ZSI6MjA0OCwiZGlnZXN0Ijoic2hhMjU2OjQ2MGMzZTI3YmUxNjNlZmU3NWRmMDQ4YzRkNGNmM2EyMmU3ZTM2M2YwMjUyMWZhMmU4MmEzYmQyNTdhNjgyZDQifV19",
"config": "eyJhcmNoaXRlY3R1cmUiOiJhbWQ2NCIsImNvbmZpZyI6eyJFbnYiOlsiUEFUSD0vdXNyL2xvY2FsL3NiaW46L3Vzci9sb2NhbC9iaW46L3Vzci9zYmluOi91c3IvYmluOi9zYmluOi9iaW4iXSwiV29ya2luZ0RpciI6Ii8iLCJPbkJ1aWxkIjpudWxsfSwiY3JlYXRlZCI6IjIwMjItMTAtMDVUMTQ6MjQ6NTguNzc0NTY2MjM2WiIsImhpc3RvcnkiOlt7ImNyZWF0ZWQiOiIyMDIyLTEwLTA1VDE0OjI0OjU4Ljc0NDY3NTEyOVoiLCJjcmVhdGVkX2J5IjoiQUREIGZpbGUtMS50eHQgL3NvbWVmaWxlLTEudHh0ICMgYnVpbGRraXQiLCJjb21tZW50IjoiYnVpbGRraXQuZG9ja2VyZmlsZS52MCJ9LHsiY3JlYXRlZCI6IjIwMjItMTAtMDVUMTQ6MjQ6NTguNzc0NTY2MjM2WiIsImNyZWF0ZWRfYnkiOiJBREQgZmlsZS0yLnR4dCAvc29tZWZpbGUtMi50eHQgIyBidWlsZGtpdCIsImNvbW1lbnQiOiJidWlsZGtpdC5kb2NrZXJmaWxlLnYwIn1dLCJvcyI6ImxpbnV4Iiwicm9vdGZzIjp7InR5cGUiOiJsYXllcnMiLCJkaWZmX2lkcyI6WyJzaGEyNTY6NDk2NWFmZmFmNDJhNzE3NDU2MTg4MmM1ZmQ4N2UyZGI2ZjBiMDdkZjUzMjQ1OWJhODZmOThhOGJkMmFmMTFkZSIsInNoYTI1Njo0NjBjM2UyN2JlMTYzZWZlNzVkZjA0OGM0ZDRjZjNhMjJlN2UzNjNmMDI1MjFmYTJlODJhM2JkMjU3YTY4MmQ0Il19fQ==",
"manifest": "eyJzY2hlbWFWZXJzaW9uIjoyLCJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC52Mitqc29uIiwiY29uZmlnIjp7Im1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uL3ZuZC5kb2NrZXIuY29udGFpbmVyLmltYWdlLnYxK2pzb24iLCJzaXplIjo2NzMsImRpZ2VzdCI6InNoYTI1NjozYzUxYjA2ZmViMGNkYThlZTYyZDBlMzc1NWVmMmE4NDk2YTZiNzFmOGE1NWIyNDVmMDdmMzFjNGJiODEzZDMxIn0sImxheWVycyI6W3sibWVkaWFUeXBlIjoiYXBwbGljYXRpb24vdm5kLmRvY2tlci5pbWFnZS5yb290ZnMuZGlmZi50YXIuZ3ppcCIsInNpemUiOjIwNDgsImRpZ2VzdCI6InNoYTI1NjpmYjZiZWVjYjc1YjM5ZjRiYjgxM2RiZjE3N2U1MDFlZGQ1ZGRiM2U2OWJiNDVjZWRlYjc4YzY3NmVlMWI3YTU5In0seyJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmltYWdlLnJvb3Rmcy5kaWZmLnRhci5nemlwIiwic2l6ZSI6MjA0OCwiZGlnZXN0Ijoic2hhMjU2OjMxOWI1ODhjZTY0MjUzYTg3YjUzM2M4ZWQwMWNmMDAyNWUwZWFjOThlN2I1MTZlMTI1MzI5NTdlMTI0NGZkZWMifV19",
"config": "eyJhcmNoaXRlY3R1cmUiOiJhbWQ2NCIsImNvbmZpZyI6eyJFbnYiOlsiUEFUSD0vdXNyL2xvY2FsL3NiaW46L3Vzci9sb2NhbC9iaW46L3Vzci9zYmluOi91c3IvYmluOi9zYmluOi9iaW4iXSwiV29ya2luZ0RpciI6Ii8iLCJPbkJ1aWxkIjpudWxsfSwiY3JlYXRlZCI6IjIwMjItMDgtMDFUMjA6MDk6MjIuNTA5NDIxNzEyWiIsImhpc3RvcnkiOlt7ImNyZWF0ZWQiOiIyMDIyLTA4LTAxVDIwOjA5OjIyLjQ4Nzg5NTUxOVoiLCJjcmVhdGVkX2J5IjoiQUREIGZpbGUtMS50eHQgL3NvbWVmaWxlLTEudHh0ICMgYnVpbGRraXQiLCJjb21tZW50IjoiYnVpbGRraXQuZG9ja2VyZmlsZS52MCJ9LHsiY3JlYXRlZCI6IjIwMjItMDgtMDFUMjA6MDk6MjIuNTA5NDIxNzEyWiIsImNyZWF0ZWRfYnkiOiJBREQgZmlsZS0yLnR4dCAvc29tZWZpbGUtMi50eHQgIyBidWlsZGtpdCIsImNvbW1lbnQiOiJidWlsZGtpdC5kb2NrZXJmaWxlLnYwIn1dLCJvcyI6ImxpbnV4Iiwicm9vdGZzIjp7InR5cGUiOiJsYXllcnMiLCJkaWZmX2lkcyI6WyJzaGEyNTY6ZmI2YmVlY2I3NWIzOWY0YmI4MTNkYmYxNzdlNTAxZWRkNWRkYjNlNjliYjQ1Y2VkZWI3OGM2NzZlZTFiN2E1OSIsInNoYTI1NjozMTliNTg4Y2U2NDI1M2E4N2I1MzNjOGVkMDFjZjAwMjVlMGVhYzk4ZTdiNTE2ZTEyNTMyOTU3ZTEyNDRmZGVjIl19fQ==",
"repoDigests": [],
"architecture": "",
"os": ""

View file

@ -55,30 +55,32 @@ var identityFiles = []parseEntry{
// IdentifyRelease parses distro-specific files to discover and raise linux distribution release details.
func IdentifyRelease(resolver source.FileResolver) *Release {
logger := log.Nested("operation", "identify-release")
for _, entry := range identityFiles {
locations, err := resolver.FilesByPath(entry.path)
if err != nil {
log.Warnf("unable to get path locations from %s: %+v", entry.path, err)
logger.WithFields("error", err, "path", entry.path).Trace("unable to get path")
continue
}
for _, location := range locations {
contentReader, err := resolver.FileContentsByLocation(location)
if err != nil {
log.Debugf("unable to get contents from %s: %s", entry.path, err)
logger.WithFields("error", err, "path", location.RealPath).Trace("unable to get contents")
continue
}
content, err := io.ReadAll(contentReader)
internal.CloseAndLogError(contentReader, location.VirtualPath)
if err != nil {
log.Warnf("unable to read %q: %+v", location.RealPath, err)
break
logger.WithFields("error", err, "path", location.RealPath).Trace("unable to read contents")
continue
}
release, err := entry.fn(string(content))
if err != nil {
log.Warnf("unable to parse %q", location.RealPath)
logger.WithFields("error", err, "path", location.RealPath).Trace("unable to parse contents")
continue
}
if release != nil {

View file

@ -6,11 +6,11 @@ import (
"github.com/scylladb/go-set/strset"
"github.com/anchore/packageurl-go"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/linux"
)
var _ FileOwner = (*AlpmMetadata)(nil)
const AlpmDBGlob = "**/var/lib/pacman/local/**/desc"
type AlpmMetadata struct {
@ -40,34 +40,6 @@ type AlpmFileRecord struct {
Digests []file.Digest `mapstructure:"digests" json:"digest,omitempty"`
}
// PackageURL returns the PURL for the specific Arch Linux package (see https://github.com/package-url/purl-spec)
func (m AlpmMetadata) PackageURL(distro *linux.Release) string {
qualifiers := map[string]string{
PURLQualifierArch: m.Architecture,
}
if m.BasePackage != "" {
qualifiers[PURLQualifierUpstream] = m.BasePackage
}
distroID := ""
if distro != nil {
distroID = distro.ID
}
return packageurl.NewPackageURL(
"alpm",
distroID,
m.Package,
m.Version,
purlQualifiers(
qualifiers,
distro,
),
"",
).ToString()
}
func (m AlpmMetadata) OwnedFiles() (result []string) {
s := strset.New()
for _, f := range m.Files {

View file

@ -65,7 +65,7 @@ func (m ApkMetadata) PackageURL(distro *linux.Release) string {
"",
m.Package,
m.Version,
purlQualifiers(
PURLQualifiers(
qualifiers,
distro,
),

View file

@ -1,48 +1,13 @@
package alpm
import (
"fmt"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source"
"github.com/anchore/syft/syft/pkg/cataloger/generic"
)
const catalogerName = "alpmdb-cataloger"
type Cataloger struct{}
// NewAlpmdbCataloger returns a new ALPM DB cataloger object.
func NewAlpmdbCataloger() *Cataloger {
return &Cataloger{}
}
// Name returns a string that uniquely describes a cataloger
func (c *Cataloger) Name() string {
return catalogerName
}
// Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing rpm db installation.
func (c *Cataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []artifact.Relationship, error) {
fileMatches, err := resolver.FilesByGlob(pkg.AlpmDBGlob)
if err != nil {
return nil, nil, fmt.Errorf("failed to find rpmdb's by glob: %w", err)
}
var pkgs []pkg.Package
for _, location := range fileMatches {
dbContentReader, err := resolver.FileContentsByLocation(location)
if err != nil {
return nil, nil, err
}
discoveredPkgs, err := parseAlpmDB(resolver, location.RealPath, dbContentReader)
internal.CloseAndLogError(dbContentReader, location.VirtualPath)
if err != nil {
return nil, nil, fmt.Errorf("unable to catalog package=%+v: %w", location.RealPath, err)
}
pkgs = append(pkgs, discoveredPkgs...)
}
return pkgs, nil, nil
func NewAlpmdbCataloger() *generic.Cataloger {
return generic.NewCataloger(catalogerName).
WithParserByGlobs(parseAlpmDB, pkg.AlpmDBGlob)
}

View file

@ -0,0 +1,52 @@
package alpm
import (
"strings"
"github.com/anchore/packageurl-go"
"github.com/anchore/syft/syft/linux"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source"
)
func newPackage(m pkg.AlpmMetadata, release *linux.Release, locations ...source.Location) pkg.Package {
p := pkg.Package{
Name: m.Package,
Version: m.Version,
Locations: source.NewLocationSet(locations...),
Type: pkg.AlpmPkg,
Licenses: strings.Split(m.License, " "),
PURL: packageURL(m, release),
MetadataType: pkg.AlpmMetadataType,
Metadata: m,
}
p.SetID()
return p
}
func packageURL(m pkg.AlpmMetadata, distro *linux.Release) string {
if distro == nil || distro.ID != "arch" {
// note: there is no namespace variation (like with debian ID_LIKE for ubuntu ID, for example)
return ""
}
qualifiers := map[string]string{
pkg.PURLQualifierArch: m.Architecture,
}
if m.BasePackage != "" {
qualifiers[pkg.PURLQualifierUpstream] = m.BasePackage
}
return packageurl.NewPackageURL(
"alpm", // `alpm` for Arch Linux and other users of the libalpm/pacman package manager. (see https://github.com/package-url/purl-spec/pull/164)
distro.ID,
m.Package,
m.Version,
pkg.PURLQualifiers(
qualifiers,
distro,
),
"",
).ToString()
}

View file

@ -1,4 +1,4 @@
package pkg
package alpm
import (
"testing"
@ -7,18 +7,32 @@ import (
"github.com/anchore/packageurl-go"
"github.com/anchore/syft/syft/linux"
"github.com/anchore/syft/syft/pkg"
)
func TestAlpmMetadata_pURL(t *testing.T) {
func Test_PackageURL(t *testing.T) {
tests := []struct {
name string
metadata AlpmMetadata
metadata pkg.AlpmMetadata
distro linux.Release
expected string
}{
{
name: "bad distro id",
metadata: pkg.AlpmMetadata{
Package: "p",
Version: "v",
Architecture: "a",
},
distro: linux.Release{
ID: "something-else",
BuildID: "rolling",
},
expected: "",
},
{
name: "gocase",
metadata: AlpmMetadata{
metadata: pkg.AlpmMetadata{
Package: "p",
Version: "v",
Architecture: "a",
@ -31,7 +45,7 @@ func TestAlpmMetadata_pURL(t *testing.T) {
},
{
name: "missing architecture",
metadata: AlpmMetadata{
metadata: pkg.AlpmMetadata{
Package: "p",
Version: "v",
},
@ -41,7 +55,7 @@ func TestAlpmMetadata_pURL(t *testing.T) {
expected: "pkg:alpm/arch/p@v?distro=arch",
},
{
metadata: AlpmMetadata{
metadata: pkg.AlpmMetadata{
Package: "python",
Version: "3.10.0",
Architecture: "any",
@ -53,7 +67,7 @@ func TestAlpmMetadata_pURL(t *testing.T) {
expected: "pkg:alpm/arch/python@3.10.0?arch=any&distro=arch-rolling",
},
{
metadata: AlpmMetadata{
metadata: pkg.AlpmMetadata{
Package: "g plus plus",
Version: "v84",
Architecture: "x86_64",
@ -66,7 +80,7 @@ func TestAlpmMetadata_pURL(t *testing.T) {
},
{
name: "add source information as qualifier",
metadata: AlpmMetadata{
metadata: pkg.AlpmMetadata{
Package: "p",
Version: "v",
Architecture: "a",
@ -82,12 +96,17 @@ func TestAlpmMetadata_pURL(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
actual := test.metadata.PackageURL(&test.distro)
actual := packageURL(test.metadata, &test.distro)
if actual != test.expected {
dmp := diffmatchpatch.New()
diffs := dmp.DiffMain(test.expected, actual, true)
t.Errorf("diff: %s", dmp.DiffPrettyText(diffs))
}
if test.expected == "" {
return
}
// verify packageurl can parse
purl, err := packageurl.FromString(actual)
if err != nil {

View file

@ -13,11 +13,15 @@ import (
"github.com/mitchellh/mapstructure"
"github.com/vbatts/go-mtree"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/generic"
"github.com/anchore/syft/syft/source"
)
var _ generic.Parser = parseAlpmDB
var (
ignoredFiles = map[string]bool{
"/set": true,
@ -27,16 +31,50 @@ var (
}
)
func newAlpmDBPackage(d *pkg.AlpmMetadata) *pkg.Package {
return &pkg.Package{
Name: d.Package,
Version: d.Version,
FoundBy: catalogerName,
Type: "alpm",
Licenses: strings.Split(d.License, " "),
MetadataType: pkg.AlpmMetadataType,
Metadata: *d,
func parseAlpmDB(resolver source.FileResolver, env *generic.Environment, reader source.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
metadata, err := parseAlpmDBEntry(reader)
if err != nil {
return nil, nil, err
}
base := filepath.Dir(reader.RealPath)
r, err := getFileReader(filepath.Join(base, "mtree"), resolver)
if err != nil {
return nil, nil, err
}
pkgFiles, err := parseMtree(r)
if err != nil {
return nil, nil, err
}
// The replace the files found the the pacman database with the files from the mtree These contain more metadata and
// thus more useful.
metadata.Files = pkgFiles
// We only really do this to get any backup database entries from the files database
files := filepath.Join(base, "files")
_, err = getFileReader(files, resolver)
if err != nil {
return nil, nil, err
}
filesMetadata, err := parseAlpmDBEntry(reader)
if err != nil {
return nil, nil, err
} else if filesMetadata != nil {
metadata.Backup = filesMetadata.Backup
}
return []pkg.Package{
newPackage(*metadata, env.LinuxRelease, reader.Location),
}, nil, nil
}
func parseAlpmDBEntry(reader io.Reader) (*pkg.AlpmMetadata, error) {
scanner := newScanner(reader)
metadata, err := parseDatabase(scanner)
if err != nil {
return nil, err
}
return metadata, nil
}
func newScanner(reader io.Reader) *bufio.Scanner {
@ -194,53 +232,3 @@ func parseMtree(r io.Reader) ([]pkg.AlpmFileRecord, error) {
}
return entries, nil
}
func parseAlpmDBEntry(reader io.Reader) (*pkg.AlpmMetadata, error) {
scanner := newScanner(reader)
metadata, err := parseDatabase(scanner)
if err != nil {
return nil, err
}
if metadata == nil {
return nil, nil
}
return metadata, nil
}
func parseAlpmDB(resolver source.FileResolver, desc string, reader io.Reader) ([]pkg.Package, error) {
metadata, err := parseAlpmDBEntry(reader)
if err != nil {
return nil, err
}
base := filepath.Dir(desc)
mtree := filepath.Join(base, "mtree")
r, err := getFileReader(mtree, resolver)
if err != nil {
return nil, err
}
pkgFiles, err := parseMtree(r)
if err != nil {
return nil, err
}
// The replace the files found the the pacman database with the files from the mtree These contain more metadata and
// thus more useful.
metadata.Files = pkgFiles
// We only really do this to get any backup database entries from the files database
files := filepath.Join(base, "files")
_, err = getFileReader(files, resolver)
if err != nil {
return nil, err
}
filesMetadata, err := parseAlpmDBEntry(reader)
if err != nil {
return nil, err
} else if filesMetadata != nil {
metadata.Backup = filesMetadata.Backup
}
p := *newAlpmDBPackage(metadata)
p.SetID()
return []pkg.Package{p}, nil
}

View file

@ -0,0 +1,151 @@
package generic
import (
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/linux"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source"
)
type processor func(resolver source.FileResolver, env Environment) []request
type request struct {
source.Location
Parser
}
// Cataloger implements the Catalog interface and is responsible for dispatching the proper parser function for
// a given path or glob pattern. This is intended to be reusable across many package cataloger types.
type Cataloger struct {
processor []processor
upstreamCataloger string
}
func (c *Cataloger) WithParserByGlobs(parser Parser, globs ...string) *Cataloger {
c.processor = append(c.processor,
func(resolver source.FileResolver, env Environment) []request {
var requests []request
for _, g := range globs {
// TODO: add more trace logging here
matches, err := resolver.FilesByGlob(g)
if err != nil {
log.Warnf("unable to process glob=%q: %+v", g, err)
continue
}
requests = append(requests, makeRequests(parser, matches)...)
}
return requests
},
)
return c
}
func (c *Cataloger) WithParserByMimeTypes(parser Parser, types ...string) *Cataloger {
c.processor = append(c.processor,
func(resolver source.FileResolver, env Environment) []request {
var requests []request
for _, t := range types {
// TODO: add more trace logging here
matches, err := resolver.FilesByMIMEType(t)
if err != nil {
log.Warnf("unable to process mimetype=%q: %+v", t, err)
continue
}
requests = append(requests, makeRequests(parser, matches)...)
}
return requests
},
)
return c
}
func (c *Cataloger) WithParserByPath(parser Parser, paths ...string) *Cataloger {
c.processor = append(c.processor,
func(resolver source.FileResolver, env Environment) []request {
var requests []request
for _, g := range paths {
// TODO: add more trace logging here
matches, err := resolver.FilesByPath(g)
if err != nil {
log.Warnf("unable to process path=%q: %+v", g, err)
continue
}
requests = append(requests, makeRequests(parser, matches)...)
}
return requests
},
)
return c
}
func makeRequests(parser Parser, locations []source.Location) []request {
var requests []request
for _, l := range locations {
requests = append(requests, request{
Location: l,
Parser: parser,
})
}
return requests
}
// NewCataloger if provided path-to-parser-function and glob-to-parser-function lookups creates a Cataloger
func NewCataloger(upstreamCataloger string) *Cataloger {
return &Cataloger{
upstreamCataloger: upstreamCataloger,
}
}
// Name returns a string that uniquely describes the upstream cataloger that this Generic Cataloger represents.
func (c *Cataloger) Name() string {
return c.upstreamCataloger
}
// Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing the catalog source.
func (c *Cataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []artifact.Relationship, error) {
var packages []pkg.Package
var relationships []artifact.Relationship
logger := log.Nested("cataloger", c.upstreamCataloger)
env := Environment{
// TODO: consider passing into the cataloger, this would affect the cataloger interface (and all implementations). This can be deferred until later.
LinuxRelease: linux.IdentifyRelease(resolver),
}
for _, req := range c.selectFiles(resolver) {
location, parser := req.Location, req.Parser
contentReader, err := resolver.FileContentsByLocation(location)
if err != nil {
logger.WithFields("location", location.RealPath, "error", err).Warn("unable to fetch contents")
continue
}
discoveredPackages, discoveredRelationships, err := parser(resolver, &env, source.NewLocationReadCloser(location, contentReader))
internal.CloseAndLogError(contentReader, location.VirtualPath)
if err != nil {
logger.WithFields("location", location.RealPath, "error", err).Warnf("cataloger failed")
continue
}
for _, p := range discoveredPackages {
p.FoundBy = c.upstreamCataloger
packages = append(packages, p)
}
relationships = append(relationships, discoveredRelationships...)
}
return packages, relationships, nil
}
// selectFiles takes a set of file trees and resolves and file references of interest for future cataloging
func (c *Cataloger) selectFiles(resolver source.FileResolver) []request {
var requests []request
for _, proc := range c.processor {
requests = append(requests, proc(resolver, Environment{})...)
}
return requests
}

View file

@ -0,0 +1,87 @@
package generic
import (
"fmt"
"io/ioutil"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source"
)
func Test_Cataloger(t *testing.T) {
allParsedPaths := make(map[string]bool)
parser := func(resolver source.FileResolver, env *Environment, reader source.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
allParsedPaths[reader.AccessPath()] = true
contents, err := ioutil.ReadAll(reader)
require.NoError(t, err)
if len(contents) == 0 {
return nil, nil, nil
}
p := pkg.Package{
Name: string(contents),
Locations: source.NewLocationSet(reader.Location),
}
r := artifact.Relationship{
From: p,
To: p,
Type: artifact.ContainsRelationship,
}
return []pkg.Package{p}, []artifact.Relationship{r}, nil
}
upstream := "some-other-cataloger"
expectedSelection := []string{"test-fixtures/last/path.txt", "test-fixtures/another-path.txt", "test-fixtures/a-path.txt", "test-fixtures/empty.txt"}
resolver := source.NewMockResolverForPaths(expectedSelection...)
cataloger := NewCataloger(upstream).
WithParserByPath(parser, "test-fixtures/another-path.txt", "test-fixtures/last/path.txt").
WithParserByGlobs(parser, "**/a-path.txt", "**/empty.txt")
actualPkgs, relationships, err := cataloger.Catalog(resolver)
assert.NoError(t, err)
expectedPkgs := make(map[string]pkg.Package)
for _, path := range expectedSelection {
require.True(t, allParsedPaths[path])
if path == "test-fixtures/empty.txt" {
continue // note: empty.txt won't become a package
}
expectedPkgs[path] = pkg.Package{
FoundBy: upstream,
Name: fmt.Sprintf("%s file contents!", path),
}
}
assert.Len(t, allParsedPaths, len(expectedSelection))
assert.Len(t, actualPkgs, len(expectedPkgs))
assert.Len(t, relationships, len(actualPkgs))
for _, p := range actualPkgs {
ls := p.Locations.ToSlice()
require.NotEmpty(t, ls)
ref := ls[0]
exP, ok := expectedPkgs[ref.RealPath]
if !ok {
t.Errorf("missing expected pkg: ref=%+v", ref)
continue
}
// assigned by the generic cataloger
if p.FoundBy != exP.FoundBy {
t.Errorf("bad upstream: %s", p.FoundBy)
}
// assigned by the parser
if exP.Name != p.Name {
t.Errorf("bad contents mapping: %+v", p.Locations)
}
}
}

View file

@ -0,0 +1,14 @@
package generic
import (
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/linux"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source"
)
type Environment struct {
LinuxRelease *linux.Release
}
type Parser func(source.FileResolver, *Environment, source.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error)

View file

@ -0,0 +1 @@
test-fixtures/a-path.txt file contents!

View file

@ -0,0 +1 @@
test-fixtures/another-path.txt file contents!

View file

@ -0,0 +1 @@
test-fixtures/last/path.txt file contents!

View file

@ -65,7 +65,7 @@ func (m DpkgMetadata) PackageURL(distro *linux.Release) string {
namespace,
m.Package,
m.Version,
purlQualifiers(
PURLQualifiers(
qualifiers,
distro,
),

View file

@ -17,7 +17,7 @@ type Package struct {
id artifact.ID `hash:"ignore"`
Name string // the package name
Version string // the version of the package
FoundBy string `cyclonedx:"foundBy"` // the specific cataloger that discovered this package
FoundBy string `hash:"ignore" cyclonedx:"foundBy"` // the specific cataloger that discovered this package
Locations source.LocationSet // the locations that lead to the discovery of this package (note: this is not necessarily the locations that make up this package)
Licenses []string // licenses discovered with the package metadata
Language Language `cyclonedx:"language"` // the language ecosystem this package belongs to (e.g. JavaScript, Python, etc)

View file

@ -190,14 +190,6 @@ func TestIDUniqueness(t *testing.T) {
},
expectedIDComparison: assert.NotEqual,
},
{
name: "foundBy is reflected",
transform: func(pkg Package) Package {
pkg.FoundBy = "new!"
return pkg
},
expectedIDComparison: assert.NotEqual,
},
{
name: "metadata mutation is reflected",
transform: func(pkg Package) Package {

View file

@ -80,7 +80,7 @@ func (m RpmMetadata) PackageURL(distro *linux.Release) string {
// for purl the epoch is a qualifier, not part of the version
// see https://github.com/package-url/purl-spec/blob/master/PURL-TYPES.rst under the RPM section
fmt.Sprintf("%s-%s", m.Version, m.Release),
purlQualifiers(
PURLQualifiers(
qualifiers,
distro,
),

View file

@ -67,7 +67,7 @@ func URL(p Package, release *linux.Release) string {
).ToString()
}
func purlQualifiers(vars map[string]string, release *linux.Release) (q packageurl.Qualifiers) {
func PURLQualifiers(vars map[string]string, release *linux.Release) (q packageurl.Qualifiers) {
keys := make([]string, 0, len(vars))
for k := range vars {
keys = append(keys, k)

View file

@ -200,24 +200,6 @@ func TestPackageURL(t *testing.T) {
expected: "pkg:maven/g.id/a@v",
},
{
name: "alpm",
distro: &linux.Release{
ID: "arch",
BuildID: "rolling",
},
pkg: Package{
Name: "linux",
Version: "5.10.0",
Type: AlpmPkg,
Metadata: AlpmMetadata{
Package: "linux",
Version: "5.10.0",
},
},
expected: "pkg:alpm/arch/linux@5.10.0?distro=arch-rolling",
},
{
name: "cocoapods",
pkg: Package{
@ -288,6 +270,7 @@ func TestPackageURL(t *testing.T) {
// testing microsoft packages is not valid for purl at this time
expectedTypes.Remove(string(KbPkg))
expectedTypes.Remove(string(PortagePkg))
expectedTypes.Remove(string(AlpmPkg))
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {

View file

@ -92,6 +92,13 @@ func NewVirtualLocationFromDirectory(responsePath, virtualResponsePath string, r
}
}
func (l Location) AccessPath() string {
if l.VirtualPath != "" {
return l.VirtualPath
}
return l.RealPath
}
func (l Location) String() string {
str := ""
if l.ref.ID() != 0 {

View file

@ -0,0 +1,15 @@
package source
import "io"
type LocationReadCloser struct {
Location
io.ReadCloser
}
func NewLocationReadCloser(location Location, reader io.ReadCloser) LocationReadCloser {
return LocationReadCloser{
Location: location,
ReadCloser: reader,
}
}