mirror of
https://github.com/anchore/syft
synced 2024-11-10 06:14:16 +00:00
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:
parent
7a8b96abc2
commit
b44f441c82
40 changed files with 495 additions and 245 deletions
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
Binary file not shown.
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
Binary file not shown.
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Binary file not shown.
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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": ""
|
||||
|
|
Binary file not shown.
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -65,7 +65,7 @@ func (m ApkMetadata) PackageURL(distro *linux.Release) string {
|
|||
"",
|
||||
m.Package,
|
||||
m.Version,
|
||||
purlQualifiers(
|
||||
PURLQualifiers(
|
||||
qualifiers,
|
||||
distro,
|
||||
),
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
52
syft/pkg/cataloger/alpm/package.go
Normal file
52
syft/pkg/cataloger/alpm/package.go
Normal 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()
|
||||
}
|
|
@ -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 {
|
|
@ -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
|
||||
}
|
||||
|
|
151
syft/pkg/cataloger/generic/cataloger.go
Normal file
151
syft/pkg/cataloger/generic/cataloger.go
Normal 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
|
||||
}
|
87
syft/pkg/cataloger/generic/cataloger_test.go
Normal file
87
syft/pkg/cataloger/generic/cataloger_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
14
syft/pkg/cataloger/generic/parser.go
Normal file
14
syft/pkg/cataloger/generic/parser.go
Normal 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)
|
1
syft/pkg/cataloger/generic/test-fixtures/a-path.txt
Normal file
1
syft/pkg/cataloger/generic/test-fixtures/a-path.txt
Normal file
|
@ -0,0 +1 @@
|
|||
test-fixtures/a-path.txt file contents!
|
|
@ -0,0 +1 @@
|
|||
test-fixtures/another-path.txt file contents!
|
0
syft/pkg/cataloger/generic/test-fixtures/empty.txt
Normal file
0
syft/pkg/cataloger/generic/test-fixtures/empty.txt
Normal file
1
syft/pkg/cataloger/generic/test-fixtures/last/path.txt
Normal file
1
syft/pkg/cataloger/generic/test-fixtures/last/path.txt
Normal file
|
@ -0,0 +1 @@
|
|||
test-fixtures/last/path.txt file contents!
|
|
@ -65,7 +65,7 @@ func (m DpkgMetadata) PackageURL(distro *linux.Release) string {
|
|||
namespace,
|
||||
m.Package,
|
||||
m.Version,
|
||||
purlQualifiers(
|
||||
PURLQualifiers(
|
||||
qualifiers,
|
||||
distro,
|
||||
),
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
15
syft/source/location_read_closer.go
Normal file
15
syft/source/location_read_closer.go
Normal 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,
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue