diff --git a/internal/constants.go b/internal/constants.go index fbf2cc9b14f..f6405d050c3 100644 --- a/internal/constants.go +++ b/internal/constants.go @@ -6,5 +6,5 @@ const ( // JSONSchemaVersion is the current schema version output by the JSON encoder // This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment. - JSONSchemaVersion = "3.3.0" + JSONSchemaVersion = "3.3.1" ) diff --git a/internal/formats/common/spdxhelpers/source_info.go b/internal/formats/common/spdxhelpers/source_info.go index 1e4a565d05d..0b6614470d5 100644 --- a/internal/formats/common/spdxhelpers/source_info.go +++ b/internal/formats/common/spdxhelpers/source_info.go @@ -37,6 +37,8 @@ func SourceInfo(p pkg.Package) string { answer = "acquired package info from PHP composer manifest" case pkg.ConanPkg: answer = "acquired package info from conan manifest" + case pkg.PortagePkg: + answer = "acquired package info from portage DB" default: answer = "acquired package info from the following paths" } diff --git a/internal/formats/common/spdxhelpers/source_info_test.go b/internal/formats/common/spdxhelpers/source_info_test.go index 1e86585d6d7..b03c3897e15 100644 --- a/internal/formats/common/spdxhelpers/source_info_test.go +++ b/internal/formats/common/spdxhelpers/source_info_test.go @@ -158,6 +158,14 @@ func Test_SourceInfo(t *testing.T) { "from conan manifest", }, }, + { + input: pkg.Package{ + Type: pkg.PortagePkg, + }, + expected: []string{ + "from portage DB", + }, + }, } var pkgTypes []pkg.Type for _, test := range tests { diff --git a/internal/formats/syftjson/model/package.go b/internal/formats/syftjson/model/package.go index 87dd1c1205b..eaf4a2e0439 100644 --- a/internal/formats/syftjson/model/package.go +++ b/internal/formats/syftjson/model/package.go @@ -157,6 +157,12 @@ func unpackMetadata(p *Package, unpacker packageMetadataUnpacker) error { return err } p.Metadata = payload + case pkg.PortageMetadataType: + var payload pkg.PortageMetadata + if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil { + return err + } + p.Metadata = payload default: log.Warnf("unknown package metadata type=%q for packageID=%q", p.MetadataType, p.ID) } diff --git a/internal/formats/syftjson/test-fixtures/snapshot/TestDirectoryEncoder.golden b/internal/formats/syftjson/test-fixtures/snapshot/TestDirectoryEncoder.golden index cd5ba604f31..f45bdbabb29 100644 --- a/internal/formats/syftjson/test-fixtures/snapshot/TestDirectoryEncoder.golden +++ b/internal/formats/syftjson/test-fixtures/snapshot/TestDirectoryEncoder.golden @@ -88,7 +88,7 @@ } }, "schema": { - "version": "3.3.0", - "url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.0.json" + "version": "3.3.1", + "url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.1.json" } } diff --git a/internal/formats/syftjson/test-fixtures/snapshot/TestEncodeFullJSONDocument.golden b/internal/formats/syftjson/test-fixtures/snapshot/TestEncodeFullJSONDocument.golden index 7c19970eb74..3a9b7534664 100644 --- a/internal/formats/syftjson/test-fixtures/snapshot/TestEncodeFullJSONDocument.golden +++ b/internal/formats/syftjson/test-fixtures/snapshot/TestEncodeFullJSONDocument.golden @@ -184,7 +184,7 @@ } }, "schema": { - "version": "3.3.0", - "url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.0.json" + "version": "3.3.1", + "url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.1.json" } } diff --git a/internal/formats/syftjson/test-fixtures/snapshot/TestImageEncoder.golden b/internal/formats/syftjson/test-fixtures/snapshot/TestImageEncoder.golden index 015a80a0112..b48787f6fa3 100644 --- a/internal/formats/syftjson/test-fixtures/snapshot/TestImageEncoder.golden +++ b/internal/formats/syftjson/test-fixtures/snapshot/TestImageEncoder.golden @@ -111,7 +111,7 @@ } }, "schema": { - "version": "3.3.0", - "url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.0.json" + "version": "3.3.1", + "url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.1.json" } } diff --git a/schema/json/README.md b/schema/json/README.md index e9fe920dba1..40af8b4cd44 100644 --- a/schema/json/README.md +++ b/schema/json/README.md @@ -25,7 +25,7 @@ Given a version number format `MODEL.REVISION.ADDITION`: When adding a new `pkg.*Metadata` that is assigned to the `pkg.Package.Metadata` struct field it is important that a few things are done: -- a new integration test case is added to `test/integration/pkg_cases_test.go` that exercises the new package type with the new metadata +- a new integration test case is added to `test/integration/catalog_packages_cases_test.go` that exercises the new package type with the new metadata - the new metadata struct is added to the `artifactMetadataContainer` struct within `schema/json/generate.go` ## Generating a New Schema @@ -36,4 +36,4 @@ Create the new schema by running `cd schema/json && go run generate.go` (note yo - If there is an existing schema for the given version and the new schema matches the existing schema, no action is taken - If there is an existing schema for the given version and the new schema **does not** match the existing schema, an error is shown indicating to increment the version appropriately (see the "Versioning" section) -***Note: never delete a JSON schema and never change an existing JSON schema once it has been published in a release!*** Only add new schemas with a newly incremented version. All previous schema files must be stored in the `schema/json/` directory. \ No newline at end of file +***Note: never delete a JSON schema and never change an existing JSON schema once it has been published in a release!*** Only add new schemas with a newly incremented version. All previous schema files must be stored in the `schema/json/` directory. diff --git a/schema/json/generate.go b/schema/json/generate.go index 96959c1050a..0f747879387 100644 --- a/schema/json/generate.go +++ b/schema/json/generate.go @@ -27,19 +27,20 @@ can be extended to include specific package metadata struct shapes in the future // When a new package metadata definition is created it will need to be manually added here. The variable name does // not matter as long as it is exported. type artifactMetadataContainer struct { - Apk pkg.ApkMetadata - Alpm pkg.AlpmMetadata - Dpkg pkg.DpkgMetadata - Gem pkg.GemMetadata - Java pkg.JavaMetadata - Npm pkg.NpmPackageJSONMetadata - Python pkg.PythonPackageMetadata - Rpm pkg.RpmdbMetadata - Cargo pkg.CargoPackageMetadata - Go pkg.GolangBinMetadata - Php pkg.PhpComposerJSONMetadata - Dart pkg.DartPubMetadata - Dotnet pkg.DotnetDepsMetadata + Apk pkg.ApkMetadata + Alpm pkg.AlpmMetadata + Dpkg pkg.DpkgMetadata + Gem pkg.GemMetadata + Java pkg.JavaMetadata + Npm pkg.NpmPackageJSONMetadata + Python pkg.PythonPackageMetadata + Rpm pkg.RpmdbMetadata + Cargo pkg.CargoPackageMetadata + Go pkg.GolangBinMetadata + Php pkg.PhpComposerJSONMetadata + Dart pkg.DartPubMetadata + Dotnet pkg.DotnetDepsMetadata + Portage pkg.PortageMetadata } func main() { diff --git a/schema/json/schema-3.3.1.json b/schema/json/schema-3.3.1.json new file mode 100644 index 00000000000..1454a27697f --- /dev/null +++ b/schema/json/schema-3.3.1.json @@ -0,0 +1,1463 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/Document", + "definitions": { + "AlpmFileRecord": { + "properties": { + "path": { + "type": "string" + }, + "type": { + "type": "string" + }, + "uid": { + "type": "string" + }, + "gid": { + "type": "string" + }, + "time": { + "type": "string", + "format": "date-time" + }, + "size": { + "type": "string" + }, + "link": { + "type": "string" + }, + "digest": { + "items": { + "$ref": "#/definitions/Digest" + }, + "type": "array" + } + }, + "additionalProperties": true, + "type": "object" + }, + "AlpmMetadata": { + "required": [ + "basepackage", + "package", + "version", + "description", + "architecture", + "size", + "packager", + "license", + "url", + "validation", + "reason", + "files", + "backup" + ], + "properties": { + "basepackage": { + "type": "string" + }, + "package": { + "type": "string" + }, + "version": { + "type": "string" + }, + "description": { + "type": "string" + }, + "architecture": { + "type": "string" + }, + "size": { + "type": "integer" + }, + "packager": { + "type": "string" + }, + "license": { + "type": "string" + }, + "url": { + "type": "string" + }, + "validation": { + "type": "string" + }, + "reason": { + "type": "integer" + }, + "files": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/AlpmFileRecord" + }, + "type": "array" + }, + "backup": { + "items": { + "$ref": "#/definitions/AlpmFileRecord" + }, + "type": "array" + } + }, + "additionalProperties": true, + "type": "object" + }, + "ApkFileRecord": { + "required": [ + "path" + ], + "properties": { + "path": { + "type": "string" + }, + "ownerUid": { + "type": "string" + }, + "ownerGid": { + "type": "string" + }, + "permissions": { + "type": "string" + }, + "digest": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/Digest" + } + }, + "additionalProperties": true, + "type": "object" + }, + "ApkMetadata": { + "required": [ + "package", + "originPackage", + "maintainer", + "version", + "license", + "architecture", + "url", + "description", + "size", + "installedSize", + "pullDependencies", + "pullChecksum", + "gitCommitOfApkPort", + "files" + ], + "properties": { + "package": { + "type": "string" + }, + "originPackage": { + "type": "string" + }, + "maintainer": { + "type": "string" + }, + "version": { + "type": "string" + }, + "license": { + "type": "string" + }, + "architecture": { + "type": "string" + }, + "url": { + "type": "string" + }, + "description": { + "type": "string" + }, + "size": { + "type": "integer" + }, + "installedSize": { + "type": "integer" + }, + "pullDependencies": { + "type": "string" + }, + "pullChecksum": { + "type": "string" + }, + "gitCommitOfApkPort": { + "type": "string" + }, + "files": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/ApkFileRecord" + }, + "type": "array" + } + }, + "additionalProperties": true, + "type": "object" + }, + "CargoPackageMetadata": { + "required": [ + "name", + "version", + "source", + "checksum", + "dependencies" + ], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "source": { + "type": "string" + }, + "checksum": { + "type": "string" + }, + "dependencies": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "additionalProperties": true, + "type": "object" + }, + "Classification": { + "required": [ + "class", + "metadata" + ], + "properties": { + "class": { + "type": "string" + }, + "metadata": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + } + }, + "additionalProperties": true, + "type": "object" + }, + "Coordinates": { + "required": [ + "path" + ], + "properties": { + "path": { + "type": "string" + }, + "layerID": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "DartPubMetadata": { + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "hosted_url": { + "type": "string" + }, + "vcs_url": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "Descriptor": { + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "configuration": { + "additionalProperties": true + } + }, + "additionalProperties": true, + "type": "object" + }, + "Digest": { + "required": [ + "algorithm", + "value" + ], + "properties": { + "algorithm": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "Document": { + "required": [ + "artifacts", + "artifactRelationships", + "source", + "distro", + "descriptor", + "schema" + ], + "properties": { + "artifacts": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/Package" + }, + "type": "array" + }, + "artifactRelationships": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/Relationship" + }, + "type": "array" + }, + "files": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/File" + }, + "type": "array" + }, + "secrets": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/Secrets" + }, + "type": "array" + }, + "source": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/Source" + }, + "distro": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/LinuxRelease" + }, + "descriptor": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/Descriptor" + }, + "schema": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/Schema" + } + }, + "additionalProperties": true, + "type": "object" + }, + "DotnetDepsMetadata": { + "required": [ + "name", + "version", + "path", + "sha512", + "hashPath" + ], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "path": { + "type": "string" + }, + "sha512": { + "type": "string" + }, + "hashPath": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "DpkgFileRecord": { + "required": [ + "path", + "isConfigFile" + ], + "properties": { + "path": { + "type": "string" + }, + "digest": { + "$ref": "#/definitions/Digest" + }, + "isConfigFile": { + "type": "boolean" + } + }, + "additionalProperties": true, + "type": "object" + }, + "DpkgMetadata": { + "required": [ + "package", + "source", + "version", + "sourceVersion", + "architecture", + "maintainer", + "installedSize", + "files" + ], + "properties": { + "package": { + "type": "string" + }, + "source": { + "type": "string" + }, + "version": { + "type": "string" + }, + "sourceVersion": { + "type": "string" + }, + "architecture": { + "type": "string" + }, + "maintainer": { + "type": "string" + }, + "installedSize": { + "type": "integer" + }, + "files": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/DpkgFileRecord" + }, + "type": "array" + } + }, + "additionalProperties": true, + "type": "object" + }, + "File": { + "required": [ + "id", + "location" + ], + "properties": { + "id": { + "type": "string" + }, + "location": { + "$ref": "#/definitions/Coordinates" + }, + "metadata": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/FileMetadataEntry" + }, + "contents": { + "type": "string" + }, + "digests": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/Digest" + }, + "type": "array" + }, + "classifications": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/Classification" + }, + "type": "array" + } + }, + "additionalProperties": true, + "type": "object" + }, + "FileMetadataEntry": { + "required": [ + "mode", + "type", + "userID", + "groupID", + "mimeType" + ], + "properties": { + "mode": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "linkDestination": { + "type": "string" + }, + "userID": { + "type": "integer" + }, + "groupID": { + "type": "integer" + }, + "mimeType": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "GemMetadata": { + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "files": { + "items": { + "type": "string" + }, + "type": "array" + }, + "authors": { + "items": { + "type": "string" + }, + "type": "array" + }, + "licenses": { + "items": { + "type": "string" + }, + "type": "array" + }, + "homepage": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "GolangBinMetadata": { + "required": [ + "goCompiledVersion", + "architecture" + ], + "properties": { + "goBuildSettings": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "goCompiledVersion": { + "type": "string" + }, + "architecture": { + "type": "string" + }, + "h1Digest": { + "type": "string" + }, + "mainModule": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "JavaManifest": { + "properties": { + "main": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "namedSections": { + "patternProperties": { + ".*": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "additionalProperties": true, + "type": "object" + }, + "JavaMetadata": { + "required": [ + "virtualPath" + ], + "properties": { + "virtualPath": { + "type": "string" + }, + "manifest": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/JavaManifest" + }, + "pomProperties": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/PomProperties" + }, + "pomProject": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/PomProject" + }, + "digest": { + "items": { + "$ref": "#/definitions/Digest" + }, + "type": "array" + } + }, + "additionalProperties": true, + "type": "object" + }, + "LinuxRelease": { + "properties": { + "prettyName": { + "type": "string" + }, + "name": { + "type": "string" + }, + "id": { + "type": "string" + }, + "idLike": { + "items": { + "type": "string" + }, + "type": "array" + }, + "version": { + "type": "string" + }, + "versionID": { + "type": "string" + }, + "versionCodename": { + "type": "string" + }, + "buildID": { + "type": "string" + }, + "imageID": { + "type": "string" + }, + "imageVersion": { + "type": "string" + }, + "variant": { + "type": "string" + }, + "variantID": { + "type": "string" + }, + "homeURL": { + "type": "string" + }, + "supportURL": { + "type": "string" + }, + "bugReportURL": { + "type": "string" + }, + "privacyPolicyURL": { + "type": "string" + }, + "cpeName": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "NpmPackageJSONMetadata": { + "required": [ + "name", + "version", + "author", + "licenses", + "homepage", + "description", + "url" + ], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "files": { + "items": { + "type": "string" + }, + "type": "array" + }, + "author": { + "type": "string" + }, + "licenses": { + "items": { + "type": "string" + }, + "type": "array" + }, + "homepage": { + "type": "string" + }, + "description": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "Package": { + "required": [ + "id", + "name", + "version", + "type", + "foundBy", + "locations", + "licenses", + "language", + "cpes", + "purl" + ], + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "type": { + "type": "string" + }, + "foundBy": { + "type": "string" + }, + "locations": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/Coordinates" + }, + "type": "array" + }, + "licenses": { + "items": { + "type": "string" + }, + "type": "array" + }, + "language": { + "type": "string" + }, + "cpes": { + "items": { + "type": "string" + }, + "type": "array" + }, + "purl": { + "type": "string" + }, + "metadataType": { + "type": "string" + }, + "metadata": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/definitions/AlpmMetadata" + }, + { + "$ref": "#/definitions/ApkMetadata" + }, + { + "$ref": "#/definitions/CargoPackageMetadata" + }, + { + "$ref": "#/definitions/DartPubMetadata" + }, + { + "$ref": "#/definitions/DotnetDepsMetadata" + }, + { + "$ref": "#/definitions/DpkgMetadata" + }, + { + "$ref": "#/definitions/GemMetadata" + }, + { + "$ref": "#/definitions/GolangBinMetadata" + }, + { + "$ref": "#/definitions/JavaMetadata" + }, + { + "$ref": "#/definitions/NpmPackageJSONMetadata" + }, + { + "$ref": "#/definitions/PhpComposerJSONMetadata" + }, + { + "$ref": "#/definitions/PortageMetadata" + }, + { + "$ref": "#/definitions/PythonPackageMetadata" + }, + { + "$ref": "#/definitions/RpmdbMetadata" + } + ] + } + }, + "additionalProperties": true, + "type": "object" + }, + "PhpComposerAuthors": { + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + }, + "email": { + "type": "string" + }, + "homepage": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "PhpComposerExternalReference": { + "required": [ + "type", + "url", + "reference" + ], + "properties": { + "type": { + "type": "string" + }, + "url": { + "type": "string" + }, + "reference": { + "type": "string" + }, + "shasum": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "PhpComposerJSONMetadata": { + "required": [ + "name", + "version", + "source", + "dist" + ], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "source": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/PhpComposerExternalReference" + }, + "dist": { + "$ref": "#/definitions/PhpComposerExternalReference" + }, + "require": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "provide": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "require-dev": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "suggest": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "notification-url": { + "type": "string" + }, + "bin": { + "items": { + "type": "string" + }, + "type": "array" + }, + "license": { + "items": { + "type": "string" + }, + "type": "array" + }, + "authors": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/PhpComposerAuthors" + }, + "type": "array" + }, + "description": { + "type": "string" + }, + "homepage": { + "type": "string" + }, + "keywords": { + "items": { + "type": "string" + }, + "type": "array" + }, + "time": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "PomParent": { + "required": [ + "groupId", + "artifactId", + "version" + ], + "properties": { + "groupId": { + "type": "string" + }, + "artifactId": { + "type": "string" + }, + "version": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "PomProject": { + "required": [ + "path", + "groupId", + "artifactId", + "version", + "name" + ], + "properties": { + "path": { + "type": "string" + }, + "parent": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/PomParent" + }, + "groupId": { + "type": "string" + }, + "artifactId": { + "type": "string" + }, + "version": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "PomProperties": { + "required": [ + "path", + "name", + "groupId", + "artifactId", + "version", + "extraFields" + ], + "properties": { + "path": { + "type": "string" + }, + "name": { + "type": "string" + }, + "groupId": { + "type": "string" + }, + "artifactId": { + "type": "string" + }, + "version": { + "type": "string" + }, + "extraFields": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + } + }, + "additionalProperties": true, + "type": "object" + }, + "PortageFileRecord": { + "required": [ + "path" + ], + "properties": { + "path": { + "type": "string" + }, + "digest": { + "$ref": "#/definitions/Digest" + } + }, + "additionalProperties": true, + "type": "object" + }, + "PortageMetadata": { + "required": [ + "package", + "version", + "installedSize", + "files" + ], + "properties": { + "package": { + "type": "string" + }, + "version": { + "type": "string" + }, + "installedSize": { + "type": "integer" + }, + "files": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/PortageFileRecord" + }, + "type": "array" + } + }, + "additionalProperties": true, + "type": "object" + }, + "PythonDirectURLOriginInfo": { + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string" + }, + "commitId": { + "type": "string" + }, + "vcs": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "PythonFileDigest": { + "required": [ + "algorithm", + "value" + ], + "properties": { + "algorithm": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "PythonFileRecord": { + "required": [ + "path" + ], + "properties": { + "path": { + "type": "string" + }, + "digest": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/PythonFileDigest" + }, + "size": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "PythonPackageMetadata": { + "required": [ + "name", + "version", + "license", + "author", + "authorEmail", + "platform", + "sitePackagesRootPath" + ], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "license": { + "type": "string" + }, + "author": { + "type": "string" + }, + "authorEmail": { + "type": "string" + }, + "platform": { + "type": "string" + }, + "files": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/PythonFileRecord" + }, + "type": "array" + }, + "sitePackagesRootPath": { + "type": "string" + }, + "topLevelPackages": { + "items": { + "type": "string" + }, + "type": "array" + }, + "directUrlOrigin": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/PythonDirectURLOriginInfo" + } + }, + "additionalProperties": true, + "type": "object" + }, + "Relationship": { + "required": [ + "parent", + "child", + "type" + ], + "properties": { + "parent": { + "type": "string" + }, + "child": { + "type": "string" + }, + "type": { + "type": "string" + }, + "metadata": { + "additionalProperties": true + } + }, + "additionalProperties": true, + "type": "object" + }, + "RpmdbFileRecord": { + "required": [ + "path", + "mode", + "size", + "digest", + "userName", + "groupName", + "flags" + ], + "properties": { + "path": { + "type": "string" + }, + "mode": { + "type": "integer" + }, + "size": { + "type": "integer" + }, + "digest": { + "$ref": "#/definitions/Digest" + }, + "userName": { + "type": "string" + }, + "groupName": { + "type": "string" + }, + "flags": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "RpmdbMetadata": { + "required": [ + "name", + "version", + "epoch", + "architecture", + "release", + "sourceRpm", + "size", + "license", + "vendor", + "files" + ], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "epoch": { + "oneOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ] + }, + "architecture": { + "type": "string" + }, + "release": { + "type": "string" + }, + "sourceRpm": { + "type": "string" + }, + "size": { + "type": "integer" + }, + "license": { + "type": "string" + }, + "vendor": { + "type": "string" + }, + "files": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/RpmdbFileRecord" + }, + "type": "array" + } + }, + "additionalProperties": true, + "type": "object" + }, + "Schema": { + "required": [ + "version", + "url" + ], + "properties": { + "version": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "SearchResult": { + "required": [ + "classification", + "lineNumber", + "lineOffset", + "seekPosition", + "length" + ], + "properties": { + "classification": { + "type": "string" + }, + "lineNumber": { + "type": "integer" + }, + "lineOffset": { + "type": "integer" + }, + "seekPosition": { + "type": "integer" + }, + "length": { + "type": "integer" + }, + "value": { + "type": "string" + } + }, + "additionalProperties": true, + "type": "object" + }, + "Secrets": { + "required": [ + "location", + "secrets" + ], + "properties": { + "location": { + "$ref": "#/definitions/Coordinates" + }, + "secrets": { + "items": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/SearchResult" + }, + "type": "array" + } + }, + "additionalProperties": true, + "type": "object" + }, + "Source": { + "required": [ + "type", + "target" + ], + "properties": { + "type": { + "type": "string" + }, + "target": { + "additionalProperties": true + } + }, + "additionalProperties": true, + "type": "object" + } + } +} diff --git a/syft/pkg/cataloger/cataloger.go b/syft/pkg/cataloger/cataloger.go index 165f7974845..c0a5c0be64c 100644 --- a/syft/pkg/cataloger/cataloger.go +++ b/syft/pkg/cataloger/cataloger.go @@ -21,6 +21,7 @@ import ( "github.com/anchore/syft/syft/pkg/cataloger/java" "github.com/anchore/syft/syft/pkg/cataloger/javascript" "github.com/anchore/syft/syft/pkg/cataloger/php" + "github.com/anchore/syft/syft/pkg/cataloger/portage" "github.com/anchore/syft/syft/pkg/cataloger/python" "github.com/anchore/syft/syft/pkg/cataloger/rpmdb" "github.com/anchore/syft/syft/pkg/cataloger/ruby" @@ -54,6 +55,7 @@ func ImageCatalogers(cfg Config) []Cataloger { apkdb.NewApkdbCataloger(), golang.NewGoModuleBinaryCataloger(), dotnet.NewDotnetDepsCataloger(), + portage.NewPortageCataloger(), }, cfg.Catalogers) } @@ -77,6 +79,7 @@ func DirectoryCatalogers(cfg Config) []Cataloger { dart.NewPubspecLockCataloger(), dotnet.NewDotnetDepsCataloger(), cpp.NewConanfileCataloger(), + portage.NewPortageCataloger(), }, cfg.Catalogers) } @@ -103,6 +106,7 @@ func AllCatalogers(cfg Config) []Cataloger { php.NewPHPComposerInstalledCataloger(), php.NewPHPComposerLockCataloger(), cpp.NewConanfileCataloger(), + portage.NewPortageCataloger(), }, cfg.Catalogers) } diff --git a/syft/pkg/cataloger/portage/cataloger.go b/syft/pkg/cataloger/portage/cataloger.go new file mode 100644 index 00000000000..a8cd5b79646 --- /dev/null +++ b/syft/pkg/cataloger/portage/cataloger.go @@ -0,0 +1,151 @@ +/* +Package portage provides a concrete Cataloger implementation for Gentoo Portage. +*/ +package portage + +import ( + "bufio" + "fmt" + "path" + "path/filepath" + "regexp" + "sort" + "strconv" + "strings" + + "github.com/anchore/syft/internal" + "github.com/anchore/syft/internal/log" + "github.com/anchore/syft/syft/artifact" + "github.com/anchore/syft/syft/file" + "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/source" +) + +var ( + cpvRe = regexp.MustCompile(`/([^/]*/[\w+][\w+-]*)-((\d+)((\.\d+)*)([a-z]?)((_(pre|p|beta|alpha|rc)\d*)*)(-r\d+)?)/CONTENTS$`) +) + +type Cataloger struct{} + +// NewPortageCataloger returns a new Portage package cataloger object. +func NewPortageCataloger() *Cataloger { + return &Cataloger{} +} + +// Name returns a string that uniquely describes a cataloger +func (c *Cataloger) Name() string { + return "portage-cataloger" +} + +// Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing portage support files. +func (c *Cataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []artifact.Relationship, error) { + dbFileMatches, err := resolver.FilesByGlob(pkg.PortageDBGlob) + if err != nil { + return nil, nil, fmt.Errorf("failed to find portage files by glob: %w", err) + } + var allPackages []pkg.Package + for _, dbLocation := range dbFileMatches { + cpvMatch := cpvRe.FindStringSubmatch(dbLocation.RealPath) + if cpvMatch == nil { + return nil, nil, fmt.Errorf("failed to match package and version in %s", dbLocation.RealPath) + } + entry := pkg.PortageMetadata{ + // ensure the default value for a collection is never nil since this may be shown as JSON + Files: make([]pkg.PortageFileRecord, 0), + Package: cpvMatch[1], + Version: cpvMatch[2], + } + + err = addFiles(resolver, dbLocation, &entry) + if err != nil { + return nil, nil, err + } + + addSize(resolver, dbLocation, &entry) + + p := pkg.Package{ + Name: entry.Package, + Version: entry.Version, + Type: pkg.PortagePkg, + MetadataType: pkg.PortageMetadataType, + Metadata: entry, + } + addLicenses(resolver, dbLocation, &p) + p.FoundBy = c.Name() + p.Locations.Add(dbLocation) + p.SetID() + allPackages = append(allPackages, p) + } + return allPackages, nil, nil +} + +func addFiles(resolver source.FileResolver, dbLocation source.Location, entry *pkg.PortageMetadata) error { + contentsReader, err := resolver.FileContentsByLocation(dbLocation) + if err != nil { + return err + } + + scanner := bufio.NewScanner(contentsReader) + for scanner.Scan() { + line := strings.Trim(scanner.Text(), "\n") + fields := strings.Split(line, " ") + + if fields[0] == "obj" { + record := pkg.PortageFileRecord{ + Path: fields[1], + } + record.Digest = &file.Digest{ + Algorithm: "md5", + Value: fields[2], + } + entry.Files = append(entry.Files, record) + } + } + return nil +} + +func addLicenses(resolver source.FileResolver, dbLocation source.Location, p *pkg.Package) { + parentPath := filepath.Dir(dbLocation.RealPath) + + location := resolver.RelativeFileByPath(dbLocation, path.Join(parentPath, "LICENSE")) + + if location != nil { + licenseReader, err := resolver.FileContentsByLocation(*location) + if err == nil { + findings := internal.NewStringSet() + scanner := bufio.NewScanner(licenseReader) + scanner.Split(bufio.ScanWords) + for scanner.Scan() { + token := scanner.Text() + if token != "||" && token != "(" && token != ")" { + findings.Add(token) + } + } + p.Licenses = findings.ToSlice() + + sort.Strings(p.Licenses) + } + } +} + +func addSize(resolver source.FileResolver, dbLocation source.Location, entry *pkg.PortageMetadata) { + parentPath := filepath.Dir(dbLocation.RealPath) + + location := resolver.RelativeFileByPath(dbLocation, path.Join(parentPath, "SIZE")) + + if location != nil { + sizeReader, err := resolver.FileContentsByLocation(*location) + if err != nil { + log.Warnf("failed to fetch portage SIZE (package=%s): %+v", entry.Package, err) + } else { + scanner := bufio.NewScanner(sizeReader) + for scanner.Scan() { + line := strings.Trim(scanner.Text(), "\n") + size, err := strconv.Atoi(line) + if err == nil { + entry.InstalledSize = size + } + } + } + } +} diff --git a/syft/pkg/cataloger/portage/cataloger_test.go b/syft/pkg/cataloger/portage/cataloger_test.go new file mode 100644 index 00000000000..26aad66fbe0 --- /dev/null +++ b/syft/pkg/cataloger/portage/cataloger_test.go @@ -0,0 +1,106 @@ +package portage + +import ( + "testing" + + "github.com/anchore/syft/syft/file" + + "github.com/anchore/stereoscope/pkg/imagetest" + "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/source" + "github.com/go-test/deep" +) + +func TestPortageCataloger(t *testing.T) { + tests := []struct { + name string + expected []pkg.Package + }{ + { + name: "go-case", + expected: []pkg.Package{ + { + Name: "app-containers/skopeo", + Version: "1.5.1", + FoundBy: "portage-cataloger", + Licenses: []string{"Apache-2.0", "BSD", "BSD-2", "CC-BY-SA-4.0", "ISC", "MIT"}, + Type: pkg.PortagePkg, + MetadataType: pkg.PortageMetadataType, + Metadata: pkg.PortageMetadata{ + Package: "app-containers/skopeo", + Version: "1.5.1", + InstalledSize: 27937835, + Files: []pkg.PortageFileRecord{ + { + Path: "/usr/bin/skopeo", + Digest: &file.Digest{ + Algorithm: "md5", + Value: "376c02bd3b22804df8fdfdc895e7dbfb", + }, + }, + { + Path: "/etc/containers/policy.json", + Digest: &file.Digest{ + Algorithm: "md5", + Value: "c01eb6950f03419e09d4fc88cb42ff6f", + }, + }, + { + Path: "/etc/containers/registries.d/default.yaml", + Digest: &file.Digest{ + Algorithm: "md5", + Value: "e6e66cd3c24623e0667f26542e0e08f6", + }, + }, + { + Path: "/var/lib/atomic/sigstore/.keep_app-containers_skopeo-0", + Digest: &file.Digest{ + Algorithm: "md5", + Value: "d41d8cd98f00b204e9800998ecf8427e", + }, + }, + }, + }, + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + + img := imagetest.GetFixtureImage(t, "docker-archive", "image-portage") + + s, err := source.NewFromImage(img, "") + if err != nil { + t.Fatal(err) + } + + c := NewPortageCataloger() + + resolver, err := s.FileResolver(source.SquashedScope) + if err != nil { + t.Errorf("could not get resolver error: %+v", err) + } + + actual, _, err := c.Catalog(resolver) + if err != nil { + t.Fatalf("failed to catalog: %+v", err) + } + + if len(actual) != len(test.expected) { + for _, a := range actual { + t.Logf(" %+v", a) + } + t.Fatalf("unexpected package count: %d!=%d", len(actual), len(test.expected)) + } + + // test remaining fields... + for _, d := range deep.Equal(actual, test.expected) { + t.Errorf("diff: %+v", d) + } + + }) + } + +} diff --git a/syft/pkg/cataloger/portage/test-fixtures/image-portage/Dockerfile b/syft/pkg/cataloger/portage/test-fixtures/image-portage/Dockerfile new file mode 100644 index 00000000000..770e60b5604 --- /dev/null +++ b/syft/pkg/cataloger/portage/test-fixtures/image-portage/Dockerfile @@ -0,0 +1,2 @@ +FROM scratch +COPY . . \ No newline at end of file diff --git a/syft/pkg/cataloger/portage/test-fixtures/image-portage/var/db/pkg/app-containers/skopeo-1.5.1/CONTENTS b/syft/pkg/cataloger/portage/test-fixtures/image-portage/var/db/pkg/app-containers/skopeo-1.5.1/CONTENTS new file mode 100644 index 00000000000..26fdf92825a --- /dev/null +++ b/syft/pkg/cataloger/portage/test-fixtures/image-portage/var/db/pkg/app-containers/skopeo-1.5.1/CONTENTS @@ -0,0 +1,13 @@ +dir /usr +dir /usr/bin +obj /usr/bin/skopeo 376c02bd3b22804df8fdfdc895e7dbfb 1649284374 +dir /etc +dir /etc/containers +obj /etc/containers/policy.json c01eb6950f03419e09d4fc88cb42ff6f 1649284375 +dir /etc/containers/registries.d +obj /etc/containers/registries.d/default.yaml e6e66cd3c24623e0667f26542e0e08f6 1649284375 +dir /var +dir /var/lib +dir /var/lib/atomic +dir /var/lib/atomic/sigstore +obj /var/lib/atomic/sigstore/.keep_app-containers_skopeo-0 d41d8cd98f00b204e9800998ecf8427e 1649284375 diff --git a/syft/pkg/cataloger/portage/test-fixtures/image-portage/var/db/pkg/app-containers/skopeo-1.5.1/LICENSE b/syft/pkg/cataloger/portage/test-fixtures/image-portage/var/db/pkg/app-containers/skopeo-1.5.1/LICENSE new file mode 100644 index 00000000000..2591f6bf271 --- /dev/null +++ b/syft/pkg/cataloger/portage/test-fixtures/image-portage/var/db/pkg/app-containers/skopeo-1.5.1/LICENSE @@ -0,0 +1 @@ +Apache-2.0 BSD BSD-2 CC-BY-SA-4.0 ISC MIT diff --git a/syft/pkg/cataloger/portage/test-fixtures/image-portage/var/db/pkg/app-containers/skopeo-1.5.1/SIZE b/syft/pkg/cataloger/portage/test-fixtures/image-portage/var/db/pkg/app-containers/skopeo-1.5.1/SIZE new file mode 100644 index 00000000000..fd07ace2237 --- /dev/null +++ b/syft/pkg/cataloger/portage/test-fixtures/image-portage/var/db/pkg/app-containers/skopeo-1.5.1/SIZE @@ -0,0 +1 @@ +27937835 diff --git a/syft/pkg/metadata.go b/syft/pkg/metadata.go index 1b0349ae0fb..8f73f38934a 100644 --- a/syft/pkg/metadata.go +++ b/syft/pkg/metadata.go @@ -26,6 +26,7 @@ const ( GolangBinMetadataType MetadataType = "GolangBinMetadata" PhpComposerJSONMetadataType MetadataType = "PhpComposerJsonMetadata" ConanaMetadataType MetadataType = "ConanaMetadataType" + PortageMetadataType MetadataType = "PortageMetadata" ) var AllMetadataTypes = []MetadataType{ @@ -44,6 +45,7 @@ var AllMetadataTypes = []MetadataType{ GolangBinMetadataType, PhpComposerJSONMetadataType, ConanaMetadataType, + PortageMetadataType, } var MetadataTypeByName = map[MetadataType]reflect.Type{ @@ -62,4 +64,5 @@ var MetadataTypeByName = map[MetadataType]reflect.Type{ GolangBinMetadataType: reflect.TypeOf(GolangBinMetadata{}), PhpComposerJSONMetadataType: reflect.TypeOf(PhpComposerJSONMetadata{}), ConanaMetadataType: reflect.TypeOf(ConanMetadata{}), + PortageMetadataType: reflect.TypeOf(PortageMetadata{}), } diff --git a/syft/pkg/portage_metadata.go b/syft/pkg/portage_metadata.go new file mode 100644 index 00000000000..97ae36772dd --- /dev/null +++ b/syft/pkg/portage_metadata.go @@ -0,0 +1,21 @@ +package pkg + +import ( + "github.com/anchore/syft/syft/file" +) + +const PortageDBGlob = "**/var/db/pkg/*/*/CONTENTS" + +// PortageMetadata represents all captured data for a Package package DB entry. +type PortageMetadata struct { + Package string `mapstructure:"Package" json:"package"` + Version string `mapstructure:"Version" json:"version"` + InstalledSize int `mapstructure:"InstalledSize" json:"installedSize" cyclonedx:"installedSize"` + Files []PortageFileRecord `json:"files"` +} + +// PortageFileRecord represents a single file attributed to a portage package. +type PortageFileRecord struct { + Path string `json:"path"` + Digest *file.Digest `json:"digest,omitempty"` +} diff --git a/syft/pkg/type.go b/syft/pkg/type.go index 72b0ad2dfaa..7bbeb5a2d28 100644 --- a/syft/pkg/type.go +++ b/syft/pkg/type.go @@ -24,6 +24,7 @@ const ( DartPubPkg Type = "dart-pub" DotnetPkg Type = "dotnet" ConanPkg Type = "conan" + PortagePkg Type = "portage" ) // AllPkgs represents all supported package types @@ -44,6 +45,7 @@ var AllPkgs = []Type{ DartPubPkg, DotnetPkg, ConanPkg, + PortagePkg, } // PackageURLType returns the PURL package type for the current package. @@ -77,6 +79,8 @@ func (t Type) PackageURLType() string { return packageurl.TypeDotnet case ConanPkg: return packageurl.TypeConan + case PortagePkg: + return "portage" default: // TODO: should this be a "generic" purl type instead? return "" @@ -122,6 +126,8 @@ func TypeByName(name string) Type { return DotnetPkg case packageurl.TypeConan: return ConanPkg + case "portage": + return PortagePkg default: return UnknownPkg } diff --git a/syft/pkg/type_test.go b/syft/pkg/type_test.go index dde84285f54..23dc961aeed 100644 --- a/syft/pkg/type_test.go +++ b/syft/pkg/type_test.go @@ -83,6 +83,7 @@ func TestTypeFromPURL(t *testing.T) { // testing microsoft packages and jenkins-plugins is not valid for purl at this time expectedTypes.Remove(string(KbPkg)) expectedTypes.Remove(string(JenkinsPluginPkg)) + expectedTypes.Remove(string(PortagePkg)) for _, test := range tests { t.Run(string(test.expected), func(t *testing.T) { diff --git a/syft/pkg/url_test.go b/syft/pkg/url_test.go index 93b31173348..9e33acd31be 100644 --- a/syft/pkg/url_test.go +++ b/syft/pkg/url_test.go @@ -233,6 +233,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)) for _, test := range tests { t.Run(test.name, func(t *testing.T) { diff --git a/test/cli/packages_cmd_test.go b/test/cli/packages_cmd_test.go index ccb64c70830..ddb441e0745 100644 --- a/test/cli/packages_cmd_test.go +++ b/test/cli/packages_cmd_test.go @@ -96,7 +96,7 @@ func TestPackagesCmdFlags(t *testing.T) { name: "squashed-scope-flag", args: []string{"packages", "-o", "json", "-s", "squashed", coverageImage}, assertions: []traitAssertion{ - assertPackageCount(33), + assertPackageCount(34), assertSuccessfulReturnCode, }, }, diff --git a/test/integration/catalog_packages_cases_test.go b/test/integration/catalog_packages_cases_test.go index 437253ebb0c..68bb300813c 100644 --- a/test/integration/catalog_packages_cases_test.go +++ b/test/integration/catalog_packages_cases_test.go @@ -277,6 +277,14 @@ var commonTestCases = []testCase{ "netbase": "5.4", }, }, + { + name: "find portage packages", + pkgType: pkg.PortagePkg, + pkgInfo: map[string]string{ + "app-containers/skopeo": "1.5.1", + }, + }, + { name: "find jenkins plugins", pkgType: pkg.JenkinsPluginPkg, diff --git a/test/integration/test-fixtures/image-pkg-coverage/pkgs/var/db/pkg/app-containers/skopeo-1.5.1/CONTENTS b/test/integration/test-fixtures/image-pkg-coverage/pkgs/var/db/pkg/app-containers/skopeo-1.5.1/CONTENTS new file mode 100644 index 00000000000..26fdf92825a --- /dev/null +++ b/test/integration/test-fixtures/image-pkg-coverage/pkgs/var/db/pkg/app-containers/skopeo-1.5.1/CONTENTS @@ -0,0 +1,13 @@ +dir /usr +dir /usr/bin +obj /usr/bin/skopeo 376c02bd3b22804df8fdfdc895e7dbfb 1649284374 +dir /etc +dir /etc/containers +obj /etc/containers/policy.json c01eb6950f03419e09d4fc88cb42ff6f 1649284375 +dir /etc/containers/registries.d +obj /etc/containers/registries.d/default.yaml e6e66cd3c24623e0667f26542e0e08f6 1649284375 +dir /var +dir /var/lib +dir /var/lib/atomic +dir /var/lib/atomic/sigstore +obj /var/lib/atomic/sigstore/.keep_app-containers_skopeo-0 d41d8cd98f00b204e9800998ecf8427e 1649284375 diff --git a/test/integration/test-fixtures/image-pkg-coverage/pkgs/var/db/pkg/app-containers/skopeo-1.5.1/LICENSE b/test/integration/test-fixtures/image-pkg-coverage/pkgs/var/db/pkg/app-containers/skopeo-1.5.1/LICENSE new file mode 100644 index 00000000000..2591f6bf271 --- /dev/null +++ b/test/integration/test-fixtures/image-pkg-coverage/pkgs/var/db/pkg/app-containers/skopeo-1.5.1/LICENSE @@ -0,0 +1 @@ +Apache-2.0 BSD BSD-2 CC-BY-SA-4.0 ISC MIT diff --git a/test/integration/test-fixtures/image-pkg-coverage/pkgs/var/db/pkg/app-containers/skopeo-1.5.1/SIZE b/test/integration/test-fixtures/image-pkg-coverage/pkgs/var/db/pkg/app-containers/skopeo-1.5.1/SIZE new file mode 100644 index 00000000000..fd07ace2237 --- /dev/null +++ b/test/integration/test-fixtures/image-pkg-coverage/pkgs/var/db/pkg/app-containers/skopeo-1.5.1/SIZE @@ -0,0 +1 @@ +27937835