diff --git a/internal/constants.go b/internal/constants.go index 274699b136f..3d903bfe7fd 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 = "5.1.0" + JSONSchemaVersion = "6.0.0" ) diff --git a/schema/json/schema-5.0.0.json b/schema/json/schema-5.0.0.json index 3b4c19135ee..0fe9ac228b6 100644 --- a/schema/json/schema-5.0.0.json +++ b/schema/json/schema-5.0.0.json @@ -1571,4 +1571,4 @@ "type": "object" } } -} +} \ No newline at end of file diff --git a/schema/json/schema-6.0.0.json b/schema/json/schema-6.0.0.json new file mode 100644 index 00000000000..454a37d2299 --- /dev/null +++ b/schema/json/schema-6.0.0.json @@ -0,0 +1,1521 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/anchore/syft/syft/formats/syftjson/model/document", + "$ref": "#/$defs/Document", + "$defs": { + "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": "#/$defs/Digest" + }, + "type": "array" + } + }, + "type": "object" + }, + "AlpmMetadata": { + "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": { + "$ref": "#/$defs/AlpmFileRecord" + }, + "type": "array" + }, + "backup": { + "items": { + "$ref": "#/$defs/AlpmFileRecord" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "basepackage", + "package", + "version", + "description", + "architecture", + "size", + "packager", + "license", + "url", + "validation", + "reason", + "files", + "backup" + ] + }, + "ApkFileRecord": { + "properties": { + "path": { + "type": "string" + }, + "ownerUid": { + "type": "string" + }, + "ownerGid": { + "type": "string" + }, + "permissions": { + "type": "string" + }, + "digest": { + "$ref": "#/$defs/Digest" + } + }, + "type": "object", + "required": [ + "path" + ] + }, + "ApkMetadata": { + "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": { + "items": { + "type": "string" + }, + "type": "array" + }, + "provides": { + "items": { + "type": "string" + }, + "type": "array" + }, + "pullChecksum": { + "type": "string" + }, + "gitCommitOfApkPort": { + "type": "string" + }, + "files": { + "items": { + "$ref": "#/$defs/ApkFileRecord" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "package", + "originPackage", + "maintainer", + "version", + "license", + "architecture", + "url", + "description", + "size", + "installedSize", + "pullDependencies", + "provides", + "pullChecksum", + "gitCommitOfApkPort", + "files" + ] + }, + "CargoPackageMetadata": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "source": { + "type": "string" + }, + "checksum": { + "type": "string" + }, + "dependencies": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "name", + "version", + "source", + "checksum", + "dependencies" + ] + }, + "Classification": { + "properties": { + "class": { + "type": "string" + }, + "virtual_path": { + "type": "string" + }, + "metadata": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object", + "required": [ + "class", + "virtual_path", + "metadata" + ] + }, + "CocoapodsMetadata": { + "properties": { + "checksum": { + "type": "string" + } + }, + "type": "object", + "required": [ + "checksum" + ] + }, + "ConanLockMetadata": { + "properties": { + "ref": { + "type": "string" + }, + "package_id": { + "type": "string" + }, + "prev": { + "type": "string" + }, + "requires": { + "type": "string" + }, + "build_requires": { + "type": "string" + }, + "py_requires": { + "type": "string" + }, + "options": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "path": { + "type": "string" + }, + "context": { + "type": "string" + } + }, + "type": "object", + "required": [ + "ref" + ] + }, + "ConanMetadata": { + "properties": { + "ref": { + "type": "string" + } + }, + "type": "object", + "required": [ + "ref" + ] + }, + "Coordinates": { + "properties": { + "path": { + "type": "string" + }, + "layerID": { + "type": "string" + } + }, + "type": "object", + "required": [ + "path" + ] + }, + "DartPubMetadata": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "hosted_url": { + "type": "string" + }, + "vcs_url": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "version" + ] + }, + "Descriptor": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "configuration": true + }, + "type": "object", + "required": [ + "name", + "version" + ] + }, + "Digest": { + "properties": { + "algorithm": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object", + "required": [ + "algorithm", + "value" + ] + }, + "Document": { + "properties": { + "artifacts": { + "items": { + "$ref": "#/$defs/Package" + }, + "type": "array" + }, + "artifactRelationships": { + "items": { + "$ref": "#/$defs/Relationship" + }, + "type": "array" + }, + "files": { + "items": { + "$ref": "#/$defs/File" + }, + "type": "array" + }, + "secrets": { + "items": { + "$ref": "#/$defs/Secrets" + }, + "type": "array" + }, + "source": { + "$ref": "#/$defs/Source" + }, + "distro": { + "$ref": "#/$defs/LinuxRelease" + }, + "descriptor": { + "$ref": "#/$defs/Descriptor" + }, + "schema": { + "$ref": "#/$defs/Schema" + } + }, + "type": "object", + "required": [ + "artifacts", + "artifactRelationships", + "source", + "distro", + "descriptor", + "schema" + ] + }, + "DotnetDepsMetadata": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "path": { + "type": "string" + }, + "sha512": { + "type": "string" + }, + "hashPath": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "version", + "path", + "sha512", + "hashPath" + ] + }, + "DpkgFileRecord": { + "properties": { + "path": { + "type": "string" + }, + "digest": { + "$ref": "#/$defs/Digest" + }, + "isConfigFile": { + "type": "boolean" + } + }, + "type": "object", + "required": [ + "path", + "isConfigFile" + ] + }, + "DpkgMetadata": { + "properties": { + "package": { + "type": "string" + }, + "source": { + "type": "string" + }, + "version": { + "type": "string" + }, + "sourceVersion": { + "type": "string" + }, + "architecture": { + "type": "string" + }, + "maintainer": { + "type": "string" + }, + "installedSize": { + "type": "integer" + }, + "files": { + "items": { + "$ref": "#/$defs/DpkgFileRecord" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "package", + "source", + "version", + "sourceVersion", + "architecture", + "maintainer", + "installedSize", + "files" + ] + }, + "File": { + "properties": { + "id": { + "type": "string" + }, + "location": { + "$ref": "#/$defs/Coordinates" + }, + "metadata": { + "$ref": "#/$defs/FileMetadataEntry" + }, + "contents": { + "type": "string" + }, + "digests": { + "items": { + "$ref": "#/$defs/Digest" + }, + "type": "array" + }, + "classifications": { + "items": { + "$ref": "#/$defs/Classification" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "id", + "location" + ] + }, + "FileMetadataEntry": { + "properties": { + "mode": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "linkDestination": { + "type": "string" + }, + "userID": { + "type": "integer" + }, + "groupID": { + "type": "integer" + }, + "mimeType": { + "type": "string" + } + }, + "type": "object", + "required": [ + "mode", + "type", + "userID", + "groupID", + "mimeType" + ] + }, + "GemMetadata": { + "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" + } + }, + "type": "object", + "required": [ + "name", + "version" + ] + }, + "GolangBinMetadata": { + "properties": { + "goBuildSettings": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "goCompiledVersion": { + "type": "string" + }, + "architecture": { + "type": "string" + }, + "h1Digest": { + "type": "string" + }, + "mainModule": { + "type": "string" + } + }, + "type": "object", + "required": [ + "goCompiledVersion", + "architecture" + ] + }, + "HackageMetadata": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "pkgHash": { + "type": "string" + }, + "snapshotURL": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "version" + ] + }, + "IDLikes": { + "items": { + "type": "string" + }, + "type": "array" + }, + "JavaManifest": { + "properties": { + "main": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "namedSections": { + "patternProperties": { + ".*": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "JavaMetadata": { + "properties": { + "virtualPath": { + "type": "string" + }, + "manifest": { + "$ref": "#/$defs/JavaManifest" + }, + "pomProperties": { + "$ref": "#/$defs/PomProperties" + }, + "pomProject": { + "$ref": "#/$defs/PomProject" + }, + "digest": { + "items": { + "$ref": "#/$defs/Digest" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "virtualPath" + ] + }, + "KbPackageMetadata": { + "properties": { + "product_id": { + "type": "string" + }, + "kb": { + "type": "string" + } + }, + "type": "object", + "required": [ + "product_id", + "kb" + ] + }, + "LinuxRelease": { + "properties": { + "prettyName": { + "type": "string" + }, + "name": { + "type": "string" + }, + "id": { + "type": "string" + }, + "idLike": { + "$ref": "#/$defs/IDLikes" + }, + "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" + } + }, + "type": "object" + }, + "NpmPackageJSONMetadata": { + "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" + }, + "private": { + "type": "boolean" + } + }, + "type": "object", + "required": [ + "name", + "version", + "author", + "licenses", + "homepage", + "description", + "url", + "private" + ] + }, + "Package": { + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "type": { + "type": "string" + }, + "foundBy": { + "type": "string" + }, + "locations": { + "items": { + "$ref": "#/$defs/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": "#/$defs/AlpmMetadata" + }, + { + "$ref": "#/$defs/ApkMetadata" + }, + { + "$ref": "#/$defs/CargoPackageMetadata" + }, + { + "$ref": "#/$defs/CocoapodsMetadata" + }, + { + "$ref": "#/$defs/ConanLockMetadata" + }, + { + "$ref": "#/$defs/ConanMetadata" + }, + { + "$ref": "#/$defs/DartPubMetadata" + }, + { + "$ref": "#/$defs/DotnetDepsMetadata" + }, + { + "$ref": "#/$defs/DpkgMetadata" + }, + { + "$ref": "#/$defs/GemMetadata" + }, + { + "$ref": "#/$defs/GolangBinMetadata" + }, + { + "$ref": "#/$defs/HackageMetadata" + }, + { + "$ref": "#/$defs/JavaMetadata" + }, + { + "$ref": "#/$defs/KbPackageMetadata" + }, + { + "$ref": "#/$defs/NpmPackageJSONMetadata" + }, + { + "$ref": "#/$defs/PhpComposerJSONMetadata" + }, + { + "$ref": "#/$defs/PortageMetadata" + }, + { + "$ref": "#/$defs/PythonPackageMetadata" + }, + { + "$ref": "#/$defs/RpmMetadata" + } + ] + } + }, + "type": "object", + "required": [ + "id", + "name", + "version", + "type", + "foundBy", + "locations", + "licenses", + "language", + "cpes", + "purl" + ] + }, + "PhpComposerAuthors": { + "properties": { + "name": { + "type": "string" + }, + "email": { + "type": "string" + }, + "homepage": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name" + ] + }, + "PhpComposerExternalReference": { + "properties": { + "type": { + "type": "string" + }, + "url": { + "type": "string" + }, + "reference": { + "type": "string" + }, + "shasum": { + "type": "string" + } + }, + "type": "object", + "required": [ + "type", + "url", + "reference" + ] + }, + "PhpComposerJSONMetadata": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "source": { + "$ref": "#/$defs/PhpComposerExternalReference" + }, + "dist": { + "$ref": "#/$defs/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": { + "$ref": "#/$defs/PhpComposerAuthors" + }, + "type": "array" + }, + "description": { + "type": "string" + }, + "homepage": { + "type": "string" + }, + "keywords": { + "items": { + "type": "string" + }, + "type": "array" + }, + "time": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "version", + "source", + "dist" + ] + }, + "PomParent": { + "properties": { + "groupId": { + "type": "string" + }, + "artifactId": { + "type": "string" + }, + "version": { + "type": "string" + } + }, + "type": "object", + "required": [ + "groupId", + "artifactId", + "version" + ] + }, + "PomProject": { + "properties": { + "path": { + "type": "string" + }, + "parent": { + "$ref": "#/$defs/PomParent" + }, + "groupId": { + "type": "string" + }, + "artifactId": { + "type": "string" + }, + "version": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "type": "object", + "required": [ + "path", + "groupId", + "artifactId", + "version", + "name" + ] + }, + "PomProperties": { + "properties": { + "path": { + "type": "string" + }, + "name": { + "type": "string" + }, + "groupId": { + "type": "string" + }, + "artifactId": { + "type": "string" + }, + "version": { + "type": "string" + }, + "extraFields": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object", + "required": [ + "path", + "name", + "groupId", + "artifactId", + "version" + ] + }, + "PortageFileRecord": { + "properties": { + "path": { + "type": "string" + }, + "digest": { + "$ref": "#/$defs/Digest" + } + }, + "type": "object", + "required": [ + "path" + ] + }, + "PortageMetadata": { + "properties": { + "installedSize": { + "type": "integer" + }, + "files": { + "items": { + "$ref": "#/$defs/PortageFileRecord" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "installedSize", + "files" + ] + }, + "PythonDirectURLOriginInfo": { + "properties": { + "url": { + "type": "string" + }, + "commitId": { + "type": "string" + }, + "vcs": { + "type": "string" + } + }, + "type": "object", + "required": [ + "url" + ] + }, + "PythonFileDigest": { + "properties": { + "algorithm": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object", + "required": [ + "algorithm", + "value" + ] + }, + "PythonFileRecord": { + "properties": { + "path": { + "type": "string" + }, + "digest": { + "$ref": "#/$defs/PythonFileDigest" + }, + "size": { + "type": "string" + } + }, + "type": "object", + "required": [ + "path" + ] + }, + "PythonPackageMetadata": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "license": { + "type": "string" + }, + "author": { + "type": "string" + }, + "authorEmail": { + "type": "string" + }, + "platform": { + "type": "string" + }, + "files": { + "items": { + "$ref": "#/$defs/PythonFileRecord" + }, + "type": "array" + }, + "sitePackagesRootPath": { + "type": "string" + }, + "topLevelPackages": { + "items": { + "type": "string" + }, + "type": "array" + }, + "directUrlOrigin": { + "$ref": "#/$defs/PythonDirectURLOriginInfo" + } + }, + "type": "object", + "required": [ + "name", + "version", + "license", + "author", + "authorEmail", + "platform", + "sitePackagesRootPath" + ] + }, + "Relationship": { + "properties": { + "parent": { + "type": "string" + }, + "child": { + "type": "string" + }, + "type": { + "type": "string" + }, + "metadata": true + }, + "type": "object", + "required": [ + "parent", + "child", + "type" + ] + }, + "RpmMetadata": { + "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" + }, + "modularityLabel": { + "type": "string" + }, + "files": { + "items": { + "$ref": "#/$defs/RpmdbFileRecord" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "name", + "version", + "epoch", + "architecture", + "release", + "sourceRpm", + "size", + "license", + "vendor", + "modularityLabel", + "files" + ] + }, + "RpmdbFileRecord": { + "properties": { + "path": { + "type": "string" + }, + "mode": { + "type": "integer" + }, + "size": { + "type": "integer" + }, + "digest": { + "$ref": "#/$defs/Digest" + }, + "userName": { + "type": "string" + }, + "groupName": { + "type": "string" + }, + "flags": { + "type": "string" + } + }, + "type": "object", + "required": [ + "path", + "mode", + "size", + "digest", + "userName", + "groupName", + "flags" + ] + }, + "Schema": { + "properties": { + "version": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "type": "object", + "required": [ + "version", + "url" + ] + }, + "SearchResult": { + "properties": { + "classification": { + "type": "string" + }, + "lineNumber": { + "type": "integer" + }, + "lineOffset": { + "type": "integer" + }, + "seekPosition": { + "type": "integer" + }, + "length": { + "type": "integer" + }, + "value": { + "type": "string" + } + }, + "type": "object", + "required": [ + "classification", + "lineNumber", + "lineOffset", + "seekPosition", + "length" + ] + }, + "Secrets": { + "properties": { + "location": { + "$ref": "#/$defs/Coordinates" + }, + "secrets": { + "items": { + "$ref": "#/$defs/SearchResult" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "location", + "secrets" + ] + }, + "Source": { + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + }, + "target": true + }, + "type": "object", + "required": [ + "id", + "type", + "target" + ] + } + } +} diff --git a/syft/artifact/relationship.go b/syft/artifact/relationship.go index 4c2fadfab02..4e2d308fd90 100644 --- a/syft/artifact/relationship.go +++ b/syft/artifact/relationship.go @@ -10,15 +10,6 @@ const ( // ContainsRelationship (supports any-to-any linkages) is a proxy for the SPDX 2.2 CONTAINS relationship. ContainsRelationship RelationshipType = "contains" - // RuntimeDependencyOfRelationship is a proxy for the SPDX 2.2.1 RUNTIME_DEPENDENCY_OF relationship. - RuntimeDependencyOfRelationship RelationshipType = "runtime-dependency-of" - - // DevDependencyOfRelationship is a proxy for the SPDX 2.2.1 DEV_DEPENDENCY_OF relationship. - DevDependencyOfRelationship RelationshipType = "dev-dependency-of" - - // BuildDependencyOfRelationship is a proxy for the SPDX 2.2.1 BUILD_DEPENDENCY_OF relationship. - BuildDependencyOfRelationship RelationshipType = "build-dependency-of" - // DependencyOfRelationship is a proxy for the SPDX 2.2.1 DEPENDENCY_OF relationship. DependencyOfRelationship RelationshipType = "dependency-of" ) diff --git a/syft/formats/common/cyclonedxhelpers/component_test.go b/syft/formats/common/cyclonedxhelpers/component_test.go index 00c685b4d70..1353c33c467 100644 --- a/syft/formats/common/cyclonedxhelpers/component_test.go +++ b/syft/formats/common/cyclonedxhelpers/component_test.go @@ -31,20 +31,21 @@ func Test_encodeComponentProperties(t *testing.T) { source.Location{Coordinates: source.Coordinates{RealPath: "test"}}, ), Metadata: pkg.ApkMetadata{ - Package: "libc-utils", - OriginPackage: "libc-dev", - Maintainer: "Natanael Copa ", - Version: "0.7.2-r0", - License: "BSD", - Architecture: "x86_64", - URL: "http://alpinelinux.org", - Description: "Meta package to pull in correct libc", - Size: 0, - InstalledSize: 4096, - PullDependencies: "musl-utils", - PullChecksum: "Q1p78yvTLG094tHE1+dToJGbmYzQE=", - GitCommitOfAport: "97b1c2842faa3bfa30f5811ffbf16d5ff9f1a479", - Files: []pkg.ApkFileRecord{}, + Package: "libc-utils", + OriginPackage: "libc-dev", + Maintainer: "Natanael Copa ", + Version: "0.7.2-r0", + License: "BSD", + Architecture: "x86_64", + URL: "http://alpinelinux.org", + Description: "Meta package to pull in correct libc", + Size: 0, + InstalledSize: 4096, + Dependencies: []string{"musl-utils"}, + Provides: []string{"so:libc.so.1"}, + Checksum: "Q1p78yvTLG094tHE1+dToJGbmYzQE=", + GitCommit: "97b1c2842faa3bfa30f5811ffbf16d5ff9f1a479", + Files: []pkg.ApkFileRecord{}, }, }, expected: &[]cyclonedx.Property{ @@ -53,8 +54,9 @@ func Test_encodeComponentProperties(t *testing.T) { {Name: "syft:metadata:gitCommitOfApkPort", Value: "97b1c2842faa3bfa30f5811ffbf16d5ff9f1a479"}, {Name: "syft:metadata:installedSize", Value: "4096"}, {Name: "syft:metadata:originPackage", Value: "libc-dev"}, + {Name: "syft:metadata:provides:0", Value: "so:libc.so.1"}, {Name: "syft:metadata:pullChecksum", Value: "Q1p78yvTLG094tHE1+dToJGbmYzQE="}, - {Name: "syft:metadata:pullDependencies", Value: "musl-utils"}, + {Name: "syft:metadata:pullDependencies:0", Value: "musl-utils"}, {Name: "syft:metadata:size", Value: "0"}, }, }, diff --git a/syft/formats/common/cyclonedxhelpers/decoder.go b/syft/formats/common/cyclonedxhelpers/decoder.go index 36d99e26014..fa234a2213f 100644 --- a/syft/formats/common/cyclonedxhelpers/decoder.go +++ b/syft/formats/common/cyclonedxhelpers/decoder.go @@ -6,6 +6,7 @@ import ( "github.com/CycloneDX/cyclonedx-go" + "github.com/anchore/packageurl-go" "github.com/anchore/syft/syft/artifact" "github.com/anchore/syft/syft/formats/common" "github.com/anchore/syft/syft/linux" @@ -88,6 +89,10 @@ func collectPackages(component *cyclonedx.Component, s *sbom.SBOM, idMap map[str case cyclonedx.ComponentTypeApplication, cyclonedx.ComponentTypeFramework, cyclonedx.ComponentTypeLibrary: p := decodeComponent(component) idMap[component.BOMRef] = p + syftID := extractSyftPacakgeID(component.BOMRef) + if syftID != "" { + idMap[syftID] = p + } // TODO there must be a better way than needing to call this manually: p.SetID() s.Artifacts.PackageCatalog.Add(*p) @@ -100,6 +105,19 @@ func collectPackages(component *cyclonedx.Component, s *sbom.SBOM, idMap map[str } } +func extractSyftPacakgeID(i string) string { + instance, err := packageurl.FromString(i) + if err != nil { + return "" + } + for _, q := range instance.Qualifiers { + if q.Key == "package-id" { + return q.Value + } + } + return "" +} + func linuxReleaseFromComponents(components []cyclonedx.Component) *linux.Release { for i := range components { component := &components[i] @@ -188,21 +206,25 @@ func collectRelationships(bom *cyclonedx.BOM, s *sbom.SBOM, idMap map[string]int return } for _, d := range *bom.Dependencies { - from, fromOk := idMap[d.Ref].(artifact.Identifiable) - if fromOk { - if d.Dependencies == nil { + from, fromExists := idMap[d.Ref].(artifact.Identifiable) + if !fromExists { + continue + } + + if d.Dependencies == nil { + continue + } + + for _, t := range *d.Dependencies { + to, toExists := idMap[t.Ref].(artifact.Identifiable) + if !toExists { continue } - for _, t := range *d.Dependencies { - to, toOk := idMap[t.Ref].(artifact.Identifiable) - if toOk { - s.Relationships = append(s.Relationships, artifact.Relationship{ - From: from, - To: to, - Type: artifact.DependencyOfRelationship, // FIXME this information is lost - }) - } - } + s.Relationships = append(s.Relationships, artifact.Relationship{ + From: from, + To: to, + Type: artifact.DependencyOfRelationship, // FIXME this information is lost + }) } } } diff --git a/syft/formats/common/cyclonedxhelpers/format.go b/syft/formats/common/cyclonedxhelpers/format.go index a22b191b2d1..b9f50abb192 100644 --- a/syft/formats/common/cyclonedxhelpers/format.go +++ b/syft/formats/common/cyclonedxhelpers/format.go @@ -10,6 +10,7 @@ import ( "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/sbom" "github.com/anchore/syft/syft/source" ) @@ -120,16 +121,11 @@ func toBomDescriptor(name, version string, srcMetadata source.Metadata) *cyclone // An example of a relationship to not include would be: OwnershipByFileOverlapRelationship. func isExpressiblePackageRelationship(ty artifact.RelationshipType) bool { switch ty { - case artifact.RuntimeDependencyOfRelationship: - return true - case artifact.DevDependencyOfRelationship: - return true - case artifact.BuildDependencyOfRelationship: - return true case artifact.DependencyOfRelationship: return true + default: + return false } - return false } func toDependencies(relationships []artifact.Relationship) []cyclonedx.Dependency { @@ -141,10 +137,21 @@ func toDependencies(relationships []artifact.Relationship) []cyclonedx.Dependenc continue } + // we only capture package-to-package relationships for now + fromPkg, ok := r.From.(*pkg.Package) + if !ok { + continue + } + + toPkg, ok := r.To.(*pkg.Package) + if !ok { + continue + } + innerDeps := []cyclonedx.Dependency{} - innerDeps = append(innerDeps, cyclonedx.Dependency{Ref: string(r.From.ID())}) + innerDeps = append(innerDeps, cyclonedx.Dependency{Ref: deriveBomRef(*fromPkg)}) result = append(result, cyclonedx.Dependency{ - Ref: string(r.To.ID()), + Ref: deriveBomRef(*toPkg), Dependencies: &innerDeps, }) } diff --git a/syft/formats/common/spdxhelpers/to_syft_model.go b/syft/formats/common/spdxhelpers/to_syft_model.go index 6eb2e5ca34b..cfc3ef729dc 100644 --- a/syft/formats/common/spdxhelpers/to_syft_model.go +++ b/syft/formats/common/spdxhelpers/to_syft_model.go @@ -186,16 +186,10 @@ func toSyftRelationships(spdxIDMap map[string]interface{}, doc *spdx.Document2_2 case ContainsRelationship: typ = artifact.ContainsRelationship to = toPackage - case BuildDependencyOfRelationship: - typ = artifact.BuildDependencyOfRelationship - to = toPackage - case RuntimeDependencyOfRelationship: - typ = artifact.RuntimeDependencyOfRelationship - to = toPackage case OtherRelationship: // Encoding uses a specifically formatted comment... if strings.Index(r.RelationshipComment, string(artifact.OwnershipByFileOverlapRelationship)) == 0 { - typ = artifact.RuntimeDependencyOfRelationship + typ = artifact.DependencyOfRelationship to = toPackage } } diff --git a/syft/formats/syftjson/format.go b/syft/formats/syftjson/format.go index c2af37ad6c5..af884e14e65 100644 --- a/syft/formats/syftjson/format.go +++ b/syft/formats/syftjson/format.go @@ -4,7 +4,7 @@ import ( "github.com/anchore/syft/syft/sbom" ) -const ID sbom.FormatID = "syft-5-json" +const ID sbom.FormatID = "syft-6-json" func Format() sbom.Format { return sbom.NewFormat( diff --git a/syft/formats/syftjson/test-fixtures/snapshot/TestDirectoryEncoder.golden b/syft/formats/syftjson/test-fixtures/snapshot/TestDirectoryEncoder.golden index 6d979abc709..b51bda2a0ab 100644 --- a/syft/formats/syftjson/test-fixtures/snapshot/TestDirectoryEncoder.golden +++ b/syft/formats/syftjson/test-fixtures/snapshot/TestDirectoryEncoder.golden @@ -89,7 +89,7 @@ } }, "schema": { - "version": "5.1.0", - "url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-5.1.0.json" + "version": "6.0.0", + "url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-6.0.0.json" } } diff --git a/syft/formats/syftjson/test-fixtures/snapshot/TestEncodeFullJSONDocument.golden b/syft/formats/syftjson/test-fixtures/snapshot/TestEncodeFullJSONDocument.golden index ac194b6c43b..4d164bef5b8 100644 --- a/syft/formats/syftjson/test-fixtures/snapshot/TestEncodeFullJSONDocument.golden +++ b/syft/formats/syftjson/test-fixtures/snapshot/TestEncodeFullJSONDocument.golden @@ -185,7 +185,7 @@ } }, "schema": { - "version": "5.1.0", - "url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-5.1.0.json" + "version": "6.0.0", + "url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-6.0.0.json" } } diff --git a/syft/formats/syftjson/test-fixtures/snapshot/TestImageEncoder.golden b/syft/formats/syftjson/test-fixtures/snapshot/TestImageEncoder.golden index c31bbaa58a7..58e455d570e 100644 --- a/syft/formats/syftjson/test-fixtures/snapshot/TestImageEncoder.golden +++ b/syft/formats/syftjson/test-fixtures/snapshot/TestImageEncoder.golden @@ -112,7 +112,7 @@ } }, "schema": { - "version": "5.1.0", - "url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-5.1.0.json" + "version": "6.0.0", + "url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-6.0.0.json" } } diff --git a/syft/formats/syftjson/to_syft_model.go b/syft/formats/syftjson/to_syft_model.go index f4b99bd67a9..c010393e4e8 100644 --- a/syft/formats/syftjson/to_syft_model.go +++ b/syft/formats/syftjson/to_syft_model.go @@ -1,6 +1,8 @@ package syftjson import ( + "strings" + "github.com/google/go-cmp/cmp" "github.com/anchore/syft/internal/log" @@ -113,12 +115,15 @@ func toSyftRelationship(idMap map[string]interface{}, relationship model.Relatio typ := artifact.RelationshipType(relationship.Type) switch typ { - case artifact.OwnershipByFileOverlapRelationship: - fallthrough - case artifact.ContainsRelationship: + case artifact.OwnershipByFileOverlapRelationship, artifact.ContainsRelationship, artifact.DependencyOfRelationship: default: - log.Warnf("unknown relationship type: %s", typ) - return nil + if !strings.Contains(string(typ), "dependency-of") { + log.Warnf("unknown relationship type: %s", typ) + return nil + } + // lets try to stay as compatible as possible with similar relationship types without dropping the relationship + log.Warnf("assuming %q for relationship type %q", artifact.DependencyOfRelationship, typ) + typ = artifact.DependencyOfRelationship } return &artifact.Relationship{ From: from, diff --git a/syft/pkg/apk_metadata.go b/syft/pkg/apk_metadata.go index 63f0015d12a..d6739f57a10 100644 --- a/syft/pkg/apk_metadata.go +++ b/syft/pkg/apk_metadata.go @@ -18,20 +18,21 @@ var _ FileOwner = (*ApkMetadata)(nil) // - https://git.alpinelinux.org/apk-tools/tree/src/package.c // - https://git.alpinelinux.org/apk-tools/tree/src/database.c type ApkMetadata struct { - Package string `mapstructure:"P" json:"package"` - OriginPackage string `mapstructure:"o" json:"originPackage" cyclonedx:"originPackage"` - Maintainer string `mapstructure:"m" json:"maintainer"` - Version string `mapstructure:"V" json:"version"` - License string `mapstructure:"L" json:"license"` - Architecture string `mapstructure:"A" json:"architecture"` - URL string `mapstructure:"U" json:"url"` - Description string `mapstructure:"T" json:"description"` - Size int `mapstructure:"S" json:"size" cyclonedx:"size"` - InstalledSize int `mapstructure:"I" json:"installedSize" cyclonedx:"installedSize"` - PullDependencies string `mapstructure:"D" json:"pullDependencies" cyclonedx:"pullDependencies"` - PullChecksum string `mapstructure:"C" json:"pullChecksum" cyclonedx:"pullChecksum"` - GitCommitOfAport string `mapstructure:"c" json:"gitCommitOfApkPort" cyclonedx:"gitCommitOfApkPort"` - Files []ApkFileRecord `json:"files"` + Package string `mapstructure:"P" json:"package"` + OriginPackage string `mapstructure:"o" json:"originPackage" cyclonedx:"originPackage"` + Maintainer string `mapstructure:"m" json:"maintainer"` + Version string `mapstructure:"V" json:"version"` + License string `mapstructure:"L" json:"license"` + Architecture string `mapstructure:"A" json:"architecture"` + URL string `mapstructure:"U" json:"url"` + Description string `mapstructure:"T" json:"description"` + Size int `mapstructure:"S" json:"size" cyclonedx:"size"` + InstalledSize int `mapstructure:"I" json:"installedSize" cyclonedx:"installedSize"` + Dependencies []string `mapstructure:"D" json:"pullDependencies" cyclonedx:"pullDependencies"` + Provides []string `mapstructure:"p" json:"provides" cyclonedx:"provides"` + Checksum string `mapstructure:"C" json:"pullChecksum" cyclonedx:"pullChecksum"` + GitCommit string `mapstructure:"c" json:"gitCommitOfApkPort" cyclonedx:"gitCommitOfApkPort"` + Files []ApkFileRecord `json:"files"` } // ApkFileRecord represents a single file listing and metadata from a APK DB entry (which may have many of these file records). diff --git a/syft/pkg/cataloger/apkdb/parse_apk_db.go b/syft/pkg/cataloger/apkdb/parse_apk_db.go index 5cc5e2b5acf..b63cefb091f 100644 --- a/syft/pkg/cataloger/apkdb/parse_apk_db.go +++ b/syft/pkg/cataloger/apkdb/parse_apk_db.go @@ -66,7 +66,7 @@ func parseApkDB(_ source.FileResolver, env *generic.Environment, reader source.L return nil, nil, fmt.Errorf("failed to parse APK DB file: %w", err) } - return pkgs, nil, nil + return pkgs, discoverPackageDependencies(pkgs), nil } // parseApkDBEntry reads and parses a single pkg.ApkMetadata element from the stream, returning nil if their are no more entries. @@ -75,6 +75,10 @@ func parseApkDB(_ source.FileResolver, env *generic.Environment, reader source.L func parseApkDBEntry(reader io.Reader) (*pkg.ApkMetadata, error) { var entry pkg.ApkMetadata pkgFields := make(map[string]interface{}) + + // We want sane defaults for collections, i.e. an empty array instead of null. + pkgFields["D"] = []string{} + pkgFields["p"] = []string{} files := make([]pkg.ApkFileRecord, 0) var fileRecord *pkg.ApkFileRecord @@ -92,6 +96,9 @@ func parseApkDBEntry(reader io.Reader) (*pkg.ApkMetadata, error) { value := strings.TrimSpace(fields[1]) switch key { + case "D", "p": + entries := strings.Split(value, " ") + pkgFields[key] = entries case "F": currentFile := "/" + value @@ -143,7 +150,20 @@ func parseApkDBEntry(reader io.Reader) (*pkg.ApkMetadata, error) { } } - if err := mapstructure.Decode(pkgFields, &entry); err != nil { + decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ + // By default, mapstructure compares field names in a *case-insensitive* manner. + // That would be the wrong approach here, since these apk files use case + // *sensitive* field names (e.g. 'P' vs. 'p'). + MatchName: func(mapKey, fieldName string) bool { + return mapKey == fieldName + }, + Result: &entry, + }) + if err != nil { + return nil, err + } + + if err := decoder.Decode(pkgFields); err != nil { return nil, fmt.Errorf("unable to parse APK metadata: %w", err) } if entry.Package == "" { @@ -174,3 +194,58 @@ func processChecksum(value string) *file.Digest { Value: value, } } + +func discoverPackageDependencies(pkgs []pkg.Package) (relationships []artifact.Relationship) { + // map["provides" string] -> packages that provide the "p" key + lookup := make(map[string][]pkg.Package) + // read "Provides" (p) and add as keys for lookup keys as well as package names + for _, p := range pkgs { + apkg, ok := p.Metadata.(pkg.ApkMetadata) + if !ok { + log.Warnf("cataloger failed to extract apk 'provides' metadata for package %+v", p.Name) + continue + } + lookup[p.Name] = append(lookup[p.Name], p) + for _, provides := range apkg.Provides { + k := stripVersionSpecifier(provides) + lookup[k] = append(lookup[k], p) + } + } + + // read "Pull Dependencies" (D) and match with keys + for _, p := range pkgs { + apkg, ok := p.Metadata.(pkg.ApkMetadata) + if !ok { + log.Warnf("cataloger failed to extract apk dependency metadata for package %+v", p.Name) + continue + } + + for _, depSpecifier := range apkg.Dependencies { + // use the lookup to find what pkg we depend on + dep := stripVersionSpecifier(depSpecifier) + for _, depPkg := range lookup[dep] { + // this is a pkg that package "p" depends on... make a relationship + relationships = append(relationships, artifact.Relationship{ + From: depPkg, + To: p, + Type: artifact.DependencyOfRelationship, + }) + } + } + } + return relationships +} + +func splitAny(s string, seps string) []string { + splitter := func(r rune) bool { + return strings.ContainsRune(seps, r) + } + return strings.FieldsFunc(s, splitter) +} + +func stripVersionSpecifier(s string) string { + // examples: + // musl>=1 --> musl + // cmd:scanelf=1.3.4-r0 --> cmd:scanelf + return splitAny(s, "<>=")[0] +} diff --git a/syft/pkg/cataloger/apkdb/parse_apk_db_test.go b/syft/pkg/cataloger/apkdb/parse_apk_db_test.go index ef8dda2c195..a5a23caeb00 100644 --- a/syft/pkg/cataloger/apkdb/parse_apk_db_test.go +++ b/syft/pkg/cataloger/apkdb/parse_apk_db_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -83,19 +84,20 @@ func TestSinglePackageDetails(t *testing.T) { { fixture: "test-fixtures/single", expected: pkg.ApkMetadata{ - Package: "musl-utils", - OriginPackage: "musl", - Version: "1.1.24-r2", - Description: "the musl c library (libc) implementation", - Maintainer: "Timo Teräs ", - License: "MIT BSD GPL2+", - Architecture: "x86_64", - URL: "https://musl.libc.org/", - Size: 37944, - InstalledSize: 151552, - PullDependencies: "scanelf so:libc.musl-x86_64.so.1", - PullChecksum: "Q1bTtF5526tETKfL+lnigzIDvm+2o=", - GitCommitOfAport: "4024cc3b29ad4c65544ad068b8f59172b5494306", + Package: "musl-utils", + OriginPackage: "musl", + Version: "1.1.24-r2", + Description: "the musl c library (libc) implementation", + Maintainer: "Timo Teräs ", + License: "MIT BSD GPL2+", + Architecture: "x86_64", + URL: "https://musl.libc.org/", + Size: 37944, + InstalledSize: 151552, + Dependencies: []string{"scanelf", "so:libc.musl-x86_64.so.1"}, + Provides: []string{"cmd:getconf", "cmd:getent", "cmd:iconv", "cmd:ldconfig", "cmd:ldd"}, + Checksum: "Q1bTtF5526tETKfL+lnigzIDvm+2o=", + GitCommit: "4024cc3b29ad4c65544ad068b8f59172b5494306", Files: []pkg.ApkFileRecord{ { Path: "/sbin", @@ -162,19 +164,20 @@ func TestSinglePackageDetails(t *testing.T) { { fixture: "test-fixtures/base", expected: pkg.ApkMetadata{ - Package: "alpine-baselayout", - OriginPackage: "alpine-baselayout", - Version: "3.2.0-r6", - Description: "Alpine base dir structure and init scripts", - Maintainer: "Natanael Copa ", - License: "GPL-2.0-only", - Architecture: "x86_64", - URL: "https://git.alpinelinux.org/cgit/aports/tree/main/alpine-baselayout", - Size: 19917, - InstalledSize: 409600, - PullDependencies: "/bin/sh so:libc.musl-x86_64.so.1", - PullChecksum: "Q1myMNfd7u5v5UTgNHeq1e31qTjZU=", - GitCommitOfAport: "e1c51734fa96fa4bac92e9f14a474324c67916fc", + Package: "alpine-baselayout", + OriginPackage: "alpine-baselayout", + Version: "3.2.0-r6", + Description: "Alpine base dir structure and init scripts", + Maintainer: "Natanael Copa ", + License: "GPL-2.0-only", + Architecture: "x86_64", + URL: "https://git.alpinelinux.org/cgit/aports/tree/main/alpine-baselayout", + Size: 19917, + InstalledSize: 409600, + Dependencies: []string{"/bin/sh", "so:libc.musl-x86_64.so.1"}, + Provides: []string{"cmd:mkmntdirs"}, + Checksum: "Q1myMNfd7u5v5UTgNHeq1e31qTjZU=", + GitCommit: "e1c51734fa96fa4bac92e9f14a474324c67916fc", Files: []pkg.ApkFileRecord{ { Path: "/dev", @@ -630,10 +633,9 @@ func TestSinglePackageDetails(t *testing.T) { } func TestMultiplePackages(t *testing.T) { - fixture := "test-fixtures/multiple" fixtureLocationSet := source.NewLocationSet(source.NewLocation(fixture)) - expected := []pkg.Package{ + expectedPkgs := []pkg.Package{ { Name: "libc-utils", Version: "0.7.2-r0", @@ -643,20 +645,21 @@ func TestMultiplePackages(t *testing.T) { Locations: fixtureLocationSet, MetadataType: pkg.ApkMetadataType, Metadata: pkg.ApkMetadata{ - Package: "libc-utils", - OriginPackage: "libc-dev", - Maintainer: "Natanael Copa ", - Version: "0.7.2-r0", - License: "BSD", - Architecture: "x86_64", - URL: "http://alpinelinux.org", - Description: "Meta package to pull in correct libc", - Size: 1175, - InstalledSize: 4096, - PullChecksum: "Q1p78yvTLG094tHE1+dToJGbmYzQE=", - GitCommitOfAport: "97b1c2842faa3bfa30f5811ffbf16d5ff9f1a479", - PullDependencies: "musl-utils", - Files: []pkg.ApkFileRecord{}, + Package: "libc-utils", + OriginPackage: "libc-dev", + Maintainer: "Natanael Copa ", + Version: "0.7.2-r0", + License: "BSD", + Architecture: "x86_64", + URL: "http://alpinelinux.org", + Description: "Meta package to pull in correct libc", + Size: 1175, + InstalledSize: 4096, + Checksum: "Q1p78yvTLG094tHE1+dToJGbmYzQE=", + GitCommit: "97b1c2842faa3bfa30f5811ffbf16d5ff9f1a479", + Dependencies: []string{"musl-utils"}, + Provides: []string{}, + Files: []pkg.ApkFileRecord{}, }, }, { @@ -668,19 +671,20 @@ func TestMultiplePackages(t *testing.T) { Locations: fixtureLocationSet, MetadataType: pkg.ApkMetadataType, Metadata: pkg.ApkMetadata{ - Package: "musl-utils", - OriginPackage: "musl", - Version: "1.1.24-r2", - Description: "the musl c library (libc) implementation", - Maintainer: "Timo Teräs ", - License: "MIT BSD GPL2+", - Architecture: "x86_64", - URL: "https://musl.libc.org/", - Size: 37944, - InstalledSize: 151552, - PullDependencies: "scanelf so:libc.musl-x86_64.so.1", - PullChecksum: "Q1bTtF5526tETKfL+lnigzIDvm+2o=", - GitCommitOfAport: "4024cc3b29ad4c65544ad068b8f59172b5494306", + Package: "musl-utils", + OriginPackage: "musl", + Version: "1.1.24-r2", + Description: "the musl c library (libc) implementation", + Maintainer: "Timo Teräs ", + License: "MIT BSD GPL2+", + Architecture: "x86_64", + URL: "https://musl.libc.org/", + Size: 37944, + InstalledSize: 151552, + GitCommit: "4024cc3b29ad4c65544ad068b8f59172b5494306", + Dependencies: []string{"scanelf", "so:libc.musl-x86_64.so.1"}, + Provides: []string{"cmd:getconf", "cmd:getent", "cmd:iconv", "cmd:ldconfig", "cmd:ldd"}, + Checksum: "Q1bTtF5526tETKfL+lnigzIDvm+2o=", Files: []pkg.ApkFileRecord{ { Path: "/sbin", @@ -746,15 +750,21 @@ func TestMultiplePackages(t *testing.T) { }, } - // TODO: relationships are not under test - var expectedRelationships []artifact.Relationship + expectedRelationships := []artifact.Relationship{ + { + From: expectedPkgs[1], // musl-utils + To: expectedPkgs[0], // libc-utils + Type: artifact.DependencyOfRelationship, + Data: nil, + }, + } env := generic.Environment{LinuxRelease: &linux.Release{ ID: "alpine", VersionID: "3.12", }} - pkgtest.TestFileParserWithEnv(t, fixture, parseApkDB, &env, expected, expectedRelationships) + pkgtest.TestFileParserWithEnv(t, fixture, parseApkDB, &env, expectedPkgs, expectedRelationships) } @@ -787,3 +797,213 @@ func Test_processChecksum(t *testing.T) { }) } } + +func Test_discoverPackageDependencies(t *testing.T) { + + tests := []struct { + name string + genFn func() ([]pkg.Package, []artifact.Relationship) + }{ + { + name: "has no dependency", + genFn: func() ([]pkg.Package, []artifact.Relationship) { + a := pkg.Package{ + Name: "package-a", + Metadata: pkg.ApkMetadata{ + Provides: []string{"a-thing"}, + }, + } + a.SetID() + b := pkg.Package{ + Name: "package-b", + Metadata: pkg.ApkMetadata{ + Provides: []string{"b-thing"}, + }, + } + b.SetID() + + return []pkg.Package{a, b}, nil + }, + }, + { + name: "has 1 dependency", + genFn: func() ([]pkg.Package, []artifact.Relationship) { + a := pkg.Package{ + Name: "package-a", + Metadata: pkg.ApkMetadata{ + Dependencies: []string{"b-thing"}, + }, + } + a.SetID() + b := pkg.Package{ + Name: "package-b", + Metadata: pkg.ApkMetadata{ + Provides: []string{"b-thing"}, + }, + } + b.SetID() + + return []pkg.Package{a, b}, []artifact.Relationship{ + { + From: b, + To: a, + Type: artifact.DependencyOfRelationship, + }, + } + }, + }, + { + name: "strip version specifiers", + genFn: func() ([]pkg.Package, []artifact.Relationship) { + a := pkg.Package{ + Name: "package-a", + Metadata: pkg.ApkMetadata{ + Dependencies: []string{"so:libc.musl-x86_64.so.1"}, + }, + } + a.SetID() + b := pkg.Package{ + Name: "package-b", + Metadata: pkg.ApkMetadata{ + Provides: []string{"so:libc.musl-x86_64.so.1=1"}, + }, + } + b.SetID() + + return []pkg.Package{a, b}, []artifact.Relationship{ + { + From: b, + To: a, + Type: artifact.DependencyOfRelationship, + }, + } + }, + }, + { + name: "depends on package name", + genFn: func() ([]pkg.Package, []artifact.Relationship) { + a := pkg.Package{ + Name: "package-a", + Metadata: pkg.ApkMetadata{ + Dependencies: []string{"musl>=1.2"}, + }, + } + a.SetID() + b := pkg.Package{ + Name: "musl", + Metadata: pkg.ApkMetadata{ + Provides: []string{"so:libc.musl-x86_64.so.1=1"}, + }, + } + b.SetID() + + return []pkg.Package{a, b}, []artifact.Relationship{ + { + From: b, + To: a, + Type: artifact.DependencyOfRelationship, + }, + } + }, + }, + { + name: "depends on package file", + genFn: func() ([]pkg.Package, []artifact.Relationship) { + a := pkg.Package{ + Name: "alpine-baselayout", + Metadata: pkg.ApkMetadata{ + Dependencies: []string{"/bin/sh"}, + }, + } + a.SetID() + b := pkg.Package{ + Name: "busybox", + Metadata: pkg.ApkMetadata{ + Provides: []string{"/bin/sh"}, + }, + } + b.SetID() + + return []pkg.Package{a, b}, []artifact.Relationship{ + { + From: b, + To: a, + Type: artifact.DependencyOfRelationship, + }, + } + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + pkgs, wantRelationships := tt.genFn() + gotRelationships := discoverPackageDependencies(pkgs) + d := cmp.Diff(wantRelationships, gotRelationships, cmpopts.IgnoreUnexported(pkg.Package{}, source.LocationSet{})) + if d != "" { + t.Fail() + t.Log(d) + } + }) + } +} + +func TestPackageDbDependenciesByParse(t *testing.T) { + tests := []struct { + fixture string + expected map[string][]string + }{ + { + fixture: "test-fixtures/installed", + expected: map[string][]string{ + "alpine-baselayout": {"alpine-baselayout-data", "busybox", "musl"}, + "apk-tools": {"musl", "ca-certificates-bundle", "musl", "libcrypto1.1", "libssl1.1", "zlib"}, + "busybox": {"musl"}, + "libc-utils": {"musl-utils"}, + "libcrypto1.1": {"musl"}, + "libssl1.1": {"musl", "libcrypto1.1"}, + "musl-utils": {"scanelf", "musl"}, + "scanelf": {"musl"}, + "ssl_client": {"musl", "libcrypto1.1", "libssl1.1"}, + "zlib": {"musl"}, + }, + }, + } + + for _, test := range tests { + t.Run(test.fixture, func(t *testing.T) { + f, err := os.Open(test.fixture) + require.NoError(t, err) + t.Cleanup(func() { require.NoError(t, f.Close()) }) + + pkgs, relationships, err := parseApkDB(nil, nil, source.LocationReadCloser{ + Location: source.NewLocation(test.fixture), + ReadCloser: f, + }) + require.NoError(t, err) + + pkgsByID := make(map[artifact.ID]pkg.Package) + for _, p := range pkgs { + p.SetID() + pkgsByID[p.ID()] = p + } + + actualDependencies := make(map[string][]string) + + for _, r := range relationships { + switch r.Type { + case artifact.DependencyOfRelationship: + to := pkgsByID[r.To.ID()] + from := pkgsByID[r.From.ID()] + actualDependencies[to.Name] = append(actualDependencies[to.Name], from.Name) + default: + t.Fatalf("unexpected relationship type: %+v", r.Type) + } + } + + if d := cmp.Diff(test.expected, actualDependencies); d != "" { + t.Fail() + t.Log(d) + } + }) + } +} diff --git a/syft/pkg/cataloger/apkdb/test-fixtures/installed b/syft/pkg/cataloger/apkdb/test-fixtures/installed new file mode 100644 index 00000000000..67fdb013026 --- /dev/null +++ b/syft/pkg/cataloger/apkdb/test-fixtures/installed @@ -0,0 +1,638 @@ +C:Q1v4QhLje3kWlC8DJj+ZfJTjlJRSU= +P:alpine-baselayout-data +V:3.2.0-r22 +A:x86_64 +S:11435 +I:73728 +T:Alpine base dir structure and init scripts +U:https://git.alpinelinux.org/cgit/aports/tree/main/alpine-baselayout +L:GPL-2.0-only +o:alpine-baselayout +m:Natanael Copa +t:1655134784 +c:cb70ca5c6d6db0399d2dd09189c5d57827bce5cd +r:alpine-baselayout +F:etc +R:fstab +Z:Q11Q7hNe8QpDS531guqCdrXBzoA/o= +R:group +Z:Q13K+olJg5ayzHSVNUkggZJXuB+9Y= +R:hostname +Z:Q16nVwYVXP/tChvUPdukVD2ifXOmc= +R:hosts +Z:Q1BD6zJKZTRWyqGnPi4tSfd3krsMU= +R:inittab +Z:Q1TsthbhW7QzWRe1E/NKwTOuD4pHc= +R:modules +Z:Q1toogjUipHGcMgECgPJX64SwUT1M= +R:mtab +a:0:0:777 +Z:Q1kiljhXXH1LlQroHsEJIkPZg2eiw= +R:passwd +Z:Q1TchuuLUfur0izvfZQZxgN/LJhB8= +R:profile +Z:Q1F3DgXUP+jNZDknmQPPb5t9FSfDg= +R:protocols +Z:Q1omKlp3vgGq2ZqYzyD/KHNdo8rDc= +R:services +Z:Q19WLCv5ItKg4MH7RWfNRh1I7byQc= +R:shadow +a:0:42:640 +Z:Q1ltrPIAW2zHeDiajsex2Bdmq3uqA= +R:shells +Z:Q1ojm2YdpCJ6B/apGDaZ/Sdb2xJkA= +R:sysctl.conf +Z:Q14upz3tfnNxZkIEsUhWn7Xoiw96g= + +C:Q1aCu0LmUDoAFSOX49uHvkYC1WasQ= +P:musl +V:1.2.3-r0 +A:x86_64 +S:383304 +I:622592 +T:the musl c library (libc) implementation +U:https://musl.libc.org/ +L:MIT +o:musl +m:Timo Teräs +t:1649396308 +c:ee13d43a53938d8a04ba787b9423f3270a3c14a7 +p:so:libc.musl-x86_64.so.1=1 +F:lib +R:ld-musl-x86_64.so.1 +a:0:0:755 +Z:Q1ZZqflKEvStJz4SXV0SDMi3wOtM0= +R:libc.musl-x86_64.so.1 +a:0:0:777 +Z:Q17yJ3JFNypA4mxhJJr0ou6CzsJVI= + +C:Q1iZ+C2JJdBlm2KKtAOkSkM7zZegY= +P:busybox +V:1.35.0-r17 +A:x86_64 +S:507831 +I:962560 +T:Size optimized toolbox of many common UNIX utilities +U:https://busybox.net/ +L:GPL-2.0-only +o:busybox +m:Sören Tempel +t:1659366884 +c:2bf6ec48e526113f87216683cd341a78af5f0b3f +D:so:libc.musl-x86_64.so.1 +p:/bin/sh cmd:busybox=1.35.0-r17 cmd:sh=1.35.0-r17 +r:busybox-initscripts +F:bin +R:busybox +a:0:0:755 +Z:Q1WUwBY0eOGgzgVxTZxJBZPyQUicI= +R:sh +a:0:0:777 +Z:Q1pcfTfDNEbNKQc2s1tia7da05M8Q= +F:etc +R:securetty +Z:Q1mB95Hq2NUTZ599RDiSsj9w5FrOU= +R:udhcpd.conf +Z:Q1EgLFjj67ou3eMqp4m3r2ZjnQ7QU= +F:etc/logrotate.d +R:acpid +Z:Q1TylyCINVmnS+A/Tead4vZhE7Bks= +F:etc/network +F:etc/network/if-down.d +F:etc/network/if-post-down.d +F:etc/network/if-post-up.d +F:etc/network/if-pre-down.d +F:etc/network/if-pre-up.d +F:etc/network/if-up.d +R:dad +a:0:0:775 +Z:Q1ORf+lPRKuYgdkBBcKoevR1t60Q4= +F:sbin +F:tmp +M:0:0:1777 +F:usr +F:usr/sbin +F:usr/share +F:usr/share/udhcpc +R:default.script +a:0:0:755 +Z:Q1t9vir/ZrX3nbSIYT9BDLWZenkVQ= +F:var +F:var/cache +F:var/cache/misc +F:var/lib +F:var/lib/udhcpd + +C:Q1l6/nM0K+cyVdqNfgkp1/c6Ylzk0= +P:alpine-baselayout +V:3.2.0-r22 +A:x86_64 +S:11126 +I:348160 +T:Alpine base dir structure and init scripts +U:https://git.alpinelinux.org/cgit/aports/tree/main/alpine-baselayout +L:GPL-2.0-only +o:alpine-baselayout +m:Natanael Copa +t:1655134784 +c:cb70ca5c6d6db0399d2dd09189c5d57827bce5cd +D:alpine-baselayout-data=3.2.0-r22 /bin/sh so:libc.musl-x86_64.so.1 +p:cmd:mkmntdirs=3.2.0-r22 +F:dev +F:dev/pts +F:dev/shm +F:etc +R:motd +Z:Q1XmduVVNURHQ27TvYp1Lr5TMtFcA= +F:etc/apk +F:etc/conf.d +F:etc/crontabs +R:root +a:0:0:600 +Z:Q1vfk1apUWI4yLJGhhNRd0kJixfvY= +F:etc/init.d +F:etc/modprobe.d +R:aliases.conf +Z:Q1WUbh6TBYNVK7e4Y+uUvLs/7viqk= +R:blacklist.conf +Z:Q14TdgFHkTdt3uQC+NBtrntOnm9n4= +R:i386.conf +Z:Q1pnay/njn6ol9cCssL7KiZZ8etlc= +R:kms.conf +Z:Q1ynbLn3GYDpvajba/ldp1niayeog= +F:etc/modules-load.d +F:etc/network +F:etc/network/if-down.d +F:etc/network/if-post-down.d +F:etc/network/if-pre-up.d +F:etc/network/if-up.d +F:etc/opt +F:etc/periodic +F:etc/periodic/15min +F:etc/periodic/daily +F:etc/periodic/hourly +F:etc/periodic/monthly +F:etc/periodic/weekly +F:etc/profile.d +R:README +Z:Q135OWsCzzvnB2fmFx62kbqm1Ax1k= +R:color_prompt.sh.disabled +Z:Q11XM9mde1Z29tWMGaOkeovD/m4uU= +R:locale.sh +Z:Q1S8j+WW71mWxfVy8ythqU7HUVoBw= +F:etc/sysctl.d +F:home +F:lib +F:lib/firmware +F:lib/mdev +F:lib/modules-load.d +F:lib/sysctl.d +R:00-alpine.conf +Z:Q1HpElzW1xEgmKfERtTy7oommnq6c= +F:media +F:media/cdrom +F:media/floppy +F:media/usb +F:mnt +F:opt +F:proc +F:root +M:0:0:700 +F:run +F:sbin +R:mkmntdirs +a:0:0:755 +Z:Q1+f8Hjd+dkHS03O6ZZaIw7mb8nLM= +F:srv +F:sys +F:tmp +M:0:0:1777 +F:usr +F:usr/lib +F:usr/lib/modules-load.d +F:usr/local +F:usr/local/bin +F:usr/local/lib +F:usr/local/share +F:usr/sbin +F:usr/share +F:usr/share/man +F:usr/share/misc +F:var +R:run +a:0:0:777 +Z:Q11/SNZz/8cK2dSKK+cJpVrZIuF4Q= +F:var/cache +F:var/cache/misc +F:var/empty +M:0:0:555 +F:var/lib +F:var/lib/misc +F:var/local +F:var/lock +F:var/lock/subsys +F:var/log +F:var/mail +F:var/opt +F:var/spool +R:mail +a:0:0:777 +Z:Q1dzbdazYZA2nTzSIG3YyNw7d4Juc= +F:var/spool/cron +R:crontabs +a:0:0:777 +Z:Q1OFZt+ZMp7j0Gny0rqSKuWJyqYmA= +F:var/tmp +M:0:0:1777 + +C:Q1FBfIjtsEmvuqoNXpShXDcm/mjzE= +P:alpine-keys +V:2.4-r1 +A:x86_64 +S:13359 +I:159744 +T:Public keys for Alpine Linux packages +U:https://alpinelinux.org +L:MIT +o:alpine-keys +m:Natanael Copa +t:1634579657 +c:aab68f8c9ab434a46710de8e12fb3206e2930a59 +r:alpine-base +F:etc +F:etc/apk +F:etc/apk/keys +R:alpine-devel@lists.alpinelinux.org-4a6a0840.rsa.pub +Z:Q1OvCFSO94z97c80mIDCxqGkh2Og4= +R:alpine-devel@lists.alpinelinux.org-5243ef4b.rsa.pub +Z:Q1v7YWZYzAWoclaLDI45jEguI7YN0= +R:alpine-devel@lists.alpinelinux.org-5261cecb.rsa.pub +Z:Q1NnGuDsdQOx4ZNYfB3N97eLyGPkI= +R:alpine-devel@lists.alpinelinux.org-6165ee59.rsa.pub +Z:Q1lZlTESNrelWTNkL/oQzmAU8a99A= +R:alpine-devel@lists.alpinelinux.org-61666e3f.rsa.pub +Z:Q1WNW6Sy87HpJ3IdemQy8pju33Kms= +F:usr +F:usr/share +F:usr/share/apk +F:usr/share/apk/keys +R:alpine-devel@lists.alpinelinux.org-4a6a0840.rsa.pub +Z:Q1OvCFSO94z97c80mIDCxqGkh2Og4= +R:alpine-devel@lists.alpinelinux.org-5243ef4b.rsa.pub +Z:Q1v7YWZYzAWoclaLDI45jEguI7YN0= +R:alpine-devel@lists.alpinelinux.org-524d27bb.rsa.pub +Z:Q1BTqS+H/UUyhQuzHwiBl47+BTKuU= +R:alpine-devel@lists.alpinelinux.org-5261cecb.rsa.pub +Z:Q1NnGuDsdQOx4ZNYfB3N97eLyGPkI= +R:alpine-devel@lists.alpinelinux.org-58199dcc.rsa.pub +Z:Q1Oaxdcsa6AYoPdLi0U4lO3J2we18= +R:alpine-devel@lists.alpinelinux.org-58cbb476.rsa.pub +Z:Q1yPq+su65ksNox3uXB+DR7P18+QU= +R:alpine-devel@lists.alpinelinux.org-58e4f17d.rsa.pub +Z:Q1MpZDNX0LeLHvSOwVUyXiXx11NN0= +R:alpine-devel@lists.alpinelinux.org-5e69ca50.rsa.pub +Z:Q1glCQ/eJbvA5xqcswdjFrWv5Fnk0= +R:alpine-devel@lists.alpinelinux.org-60ac2099.rsa.pub +Z:Q1XUdDEoNTtjlvrS+iunk6ziFgIpU= +R:alpine-devel@lists.alpinelinux.org-6165ee59.rsa.pub +Z:Q1lZlTESNrelWTNkL/oQzmAU8a99A= +R:alpine-devel@lists.alpinelinux.org-61666e3f.rsa.pub +Z:Q1WNW6Sy87HpJ3IdemQy8pju33Kms= +R:alpine-devel@lists.alpinelinux.org-616a9724.rsa.pub +Z:Q1I9Dy6hryacL2YWXg+KlE6WvwEd4= +R:alpine-devel@lists.alpinelinux.org-616abc23.rsa.pub +Z:Q1NSnsgmcMbU4g7j5JaNs0tVHpHVA= +R:alpine-devel@lists.alpinelinux.org-616ac3bc.rsa.pub +Z:Q1VaMBBk4Rxv6boPLKF+I085Q8y2E= +R:alpine-devel@lists.alpinelinux.org-616adfeb.rsa.pub +Z:Q13hJBMHAUquPbp5jpAPFjQI2Y1vQ= +R:alpine-devel@lists.alpinelinux.org-616ae350.rsa.pub +Z:Q1V/a5P9pKRJb6tihE3e8O6xaPgLU= +R:alpine-devel@lists.alpinelinux.org-616db30d.rsa.pub +Z:Q13wLJrcKQajql5a1p9Q45U+ZXENA= +F:usr/share/apk/keys/aarch64 +R:alpine-devel@lists.alpinelinux.org-58199dcc.rsa.pub +a:0:0:777 +Z:Q17j9nWJkQ+wfIuVQzIFrmFZ7fSOc= +R:alpine-devel@lists.alpinelinux.org-616ae350.rsa.pub +a:0:0:777 +Z:Q1snr+Q1UbfHyCr/cmmtVvMIS7SGs= +F:usr/share/apk/keys/armhf +R:alpine-devel@lists.alpinelinux.org-524d27bb.rsa.pub +a:0:0:777 +Z:Q1U9QtsdN+rYZ9Zh76EfXy00JZHMg= +R:alpine-devel@lists.alpinelinux.org-616a9724.rsa.pub +a:0:0:777 +Z:Q1bC+AdQ0qWBTmefXiI0PvmYOJoVQ= +F:usr/share/apk/keys/armv7 +R:alpine-devel@lists.alpinelinux.org-524d27bb.rsa.pub +a:0:0:777 +Z:Q1U9QtsdN+rYZ9Zh76EfXy00JZHMg= +R:alpine-devel@lists.alpinelinux.org-616adfeb.rsa.pub +a:0:0:777 +Z:Q1xbIVu7ScwqGHxXGwI22aSe5OdUY= +F:usr/share/apk/keys/mips64 +R:alpine-devel@lists.alpinelinux.org-5e69ca50.rsa.pub +a:0:0:777 +Z:Q1hCZdFx+LvzbLtPs753je78gEEBQ= +F:usr/share/apk/keys/ppc64le +R:alpine-devel@lists.alpinelinux.org-58cbb476.rsa.pub +a:0:0:777 +Z:Q1t21dhCLbTJmAHXSCeOMq/2vfSgo= +R:alpine-devel@lists.alpinelinux.org-616abc23.rsa.pub +a:0:0:777 +Z:Q1PS9zNIPJanC8qcsc5qarEWqhV5Q= +F:usr/share/apk/keys/riscv64 +R:alpine-devel@lists.alpinelinux.org-60ac2099.rsa.pub +a:0:0:777 +Z:Q1NVPbZavaXpsItFwQYDWbpor7yYE= +R:alpine-devel@lists.alpinelinux.org-616db30d.rsa.pub +a:0:0:777 +Z:Q1U6tfuKRy5J8C6iaKPMZaT/e8tbA= +F:usr/share/apk/keys/s390x +R:alpine-devel@lists.alpinelinux.org-58e4f17d.rsa.pub +a:0:0:777 +Z:Q1sjbV2r2w0Ih2vwdzC4Jq6UI7cMQ= +R:alpine-devel@lists.alpinelinux.org-616ac3bc.rsa.pub +a:0:0:777 +Z:Q1l09xa7RnbOIC1dI9FqbaCfS/GXY= +F:usr/share/apk/keys/x86 +R:alpine-devel@lists.alpinelinux.org-4a6a0840.rsa.pub +a:0:0:777 +Z:Q1Ii51i7Nrc4uft14HhqugaUqdH64= +R:alpine-devel@lists.alpinelinux.org-5243ef4b.rsa.pub +a:0:0:777 +Z:Q1Y49eVxhpvftbQ3yAdvlLfcrPLTU= +R:alpine-devel@lists.alpinelinux.org-61666e3f.rsa.pub +a:0:0:777 +Z:Q1HjdvcVkpBZzr1aSe3p7oQfAtm/E= +F:usr/share/apk/keys/x86_64 +R:alpine-devel@lists.alpinelinux.org-4a6a0840.rsa.pub +a:0:0:777 +Z:Q1Ii51i7Nrc4uft14HhqugaUqdH64= +R:alpine-devel@lists.alpinelinux.org-5261cecb.rsa.pub +a:0:0:777 +Z:Q1AUFY+fwSBTcrYetjT7NHvafrSQc= +R:alpine-devel@lists.alpinelinux.org-6165ee59.rsa.pub +a:0:0:777 +Z:Q1qKA23VzMUDle+Dqnrr5Kz+Xvty4= + +C:Q1huqjigIP7ZNHBueDUmNnT6PpToI= +P:ca-certificates-bundle +V:20220614-r0 +A:x86_64 +S:125920 +I:233472 +T:Pre generated bundle of Mozilla certificates +U:https://www.mozilla.org/en-US/about/governance/policies/security-group/certs/ +L:MPL-2.0 AND MIT +o:ca-certificates +m:Natanael Copa +t:1659254961 +c:bb51fa7743320ac61f76e181cca84daa9977573e +p:ca-certificates-cacert=20220614-r0 +r:libressl2.7-libcrypto +F:etc +F:etc/ssl +R:cert.pem +a:0:0:777 +Z:Q1Nj6gTBdkZpTFW/obJGdpfvK0StA= +F:etc/ssl/certs +R:ca-certificates.crt +Z:Q1D8ljYj7pXsRq4d/eHGNYB0GY1+I= + +C:Q1rd80DWg+fcm+GFn06ahfUUPUshw= +P:libcrypto1.1 +V:1.1.1q-r0 +A:x86_64 +S:1212577 +I:2772992 +T:Crypto library from openssl +U:https://www.openssl.org/ +L:OpenSSL +o:openssl +m:Timo Teras +t:1657033577 +c:26153b65138c876d57e81750f6de6baab6d5bd5b +D:so:libc.musl-x86_64.so.1 +p:so:libcrypto.so.1.1=1.1 +r:libressl2.7-libcrypto +F:etc +F:etc/ssl +R:ct_log_list.cnf +Z:Q1olh8TpdAi2QnTl4FK3TjdUiSwTo= +R:ct_log_list.cnf.dist +Z:Q1olh8TpdAi2QnTl4FK3TjdUiSwTo= +R:openssl.cnf +Z:Q1wGuxVEOK9iGLj1i8D3BSBnT7MJA= +R:openssl.cnf.dist +Z:Q1wGuxVEOK9iGLj1i8D3BSBnT7MJA= +F:etc/ssl/certs +F:etc/ssl/misc +R:CA.pl +a:0:0:755 +Z:Q1IACevKhK93GYBHp96Ie26jgZ17s= +R:tsget +a:0:0:777 +Z:Q13NVgfr7dQUuGYxur0tNalH6EIjU= +R:tsget.pl +a:0:0:755 +Z:Q15sBrpDGKgjg82+bFLL8ivnu5pbQ= +F:etc/ssl/private +F:lib +R:libcrypto.so.1.1 +a:0:0:755 +Z:Q1f/TrTwFtSlD1k639L+FfsTkJWPY= +F:usr +F:usr/lib +R:libcrypto.so.1.1 +a:0:0:777 +Z:Q1T2si+c7ts7sgDxQYve4B3i1Dgo0= +F:usr/lib/engines-1.1 +R:afalg.so +a:0:0:755 +Z:Q1Oljrwcq5h1sKPXcImsYYWLqm9SA= +R:capi.so +a:0:0:755 +Z:Q1Xtf9a1EQ1VWfygx1oNhMvNoNZzw= +R:padlock.so +a:0:0:755 +Z:Q1ttkhyM+fT6wkUcV9zgXXTTF7VNo= + +C:Q1ciplPwPAKDa19jkbxYjiiv+G5Es= +P:libssl1.1 +V:1.1.1q-r0 +A:x86_64 +S:213294 +I:540672 +T:SSL shared libraries +U:https://www.openssl.org/ +L:OpenSSL +o:openssl +m:Timo Teras +t:1657033577 +c:26153b65138c876d57e81750f6de6baab6d5bd5b +D:so:libc.musl-x86_64.so.1 so:libcrypto.so.1.1 +p:so:libssl.so.1.1=1.1 +r:libressl +F:lib +R:libssl.so.1.1 +a:0:0:755 +Z:Q1/on1tWApiZJE4XvUyE6MTFO2MY0= +F:usr +F:usr/lib +R:libssl.so.1.1 +a:0:0:777 +Z:Q18j35pe3yp6HOgMih1wlGP1/mm2c= + +C:Q1KWJXawaNPiINHfdzCg/FrEmiAaU= +P:ssl_client +V:1.35.0-r17 +A:x86_64 +S:5004 +I:28672 +T:EXternal ssl_client for busybox wget +U:https://busybox.net/ +L:GPL-2.0-only +o:busybox +m:Sören Tempel +t:1659366884 +c:2bf6ec48e526113f87216683cd341a78af5f0b3f +D:so:libc.musl-x86_64.so.1 so:libcrypto.so.1.1 so:libssl.so.1.1 +p:cmd:ssl_client=1.35.0-r17 +i:busybox=1.35.0-r17 libssl1.1 +r:busybox-initscripts +F:usr +F:usr/bin +R:ssl_client +a:0:0:755 +Z:Q1C6qA8RFt5eagesbaqu4plc6Ctyc= + +C:Q1Ekuqm/0CPywDCKEbEwhsPCw+z9E= +P:zlib +V:1.2.12-r3 +A:x86_64 +S:53346 +I:110592 +T:A compression/decompression Library +U:https://zlib.net/ +L:Zlib +o:zlib +m:Natanael Copa +t:1660030129 +c:57ce38bde7ce42964b664c137935cf2de803ac44 +D:so:libc.musl-x86_64.so.1 +p:so:libz.so.1=1.2.12 +F:lib +R:libz.so.1 +a:0:0:777 +Z:Q1+aBjyJ7dmLatVkyqCNnAChlDZh8= +R:libz.so.1.2.12 +a:0:0:755 +Z:Q1x/qx/7zlM20k7fLfVee7A4WLOC8= + +C:Q1VFFFWMKjB9aRkehIATc5kwgAhlU= +P:apk-tools +V:2.12.9-r3 +A:x86_64 +S:120745 +I:307200 +T:Alpine Package Keeper - package manager for alpine +U:https://gitlab.alpinelinux.org/alpine/apk-tools +L:GPL-2.0-only +o:apk-tools +m:Natanael Copa +t:1652592000 +c:34d90ac8388e88126893f5d27ea35d304e65e5ab +D:musl>=1.2 ca-certificates-bundle so:libc.musl-x86_64.so.1 so:libcrypto.so.1.1 so:libssl.so.1.1 so:libz.so.1 +p:so:libapk.so.3.12.0=3.12.0 cmd:apk=2.12.9-r3 +F:etc +F:etc/apk +F:etc/apk/keys +F:etc/apk/protected_paths.d +F:lib +R:libapk.so.3.12.0 +a:0:0:755 +Z:Q1kVeagJvcGMIKp8ijGOxaZD08ONs= +F:sbin +R:apk +a:0:0:755 +Z:Q1P1oUBG/VMMhnndf2fBXsZXBjHVE= +F:var +F:var/cache +F:var/cache/misc +F:var/lib +F:var/lib/apk + +C:Q1Gcqe+ND8DFOlhM3R0o5KyZjR2oE= +P:scanelf +V:1.3.4-r0 +A:x86_64 +S:36745 +I:94208 +T:Scan ELF binaries for stuff +U:https://wiki.gentoo.org/wiki/Hardened/PaX_Utilities +L:GPL-2.0-only +o:pax-utils +m:Natanael Copa +t:1651005390 +c:d7ae612a3cc5f827289d915783b4cbf8c7207947 +D:so:libc.musl-x86_64.so.1 +p:cmd:scanelf=1.3.4-r0 +r:pax-utils +F:usr +F:usr/bin +R:scanelf +a:0:0:755 +Z:Q1YPb72qHJJvTH6mJkN9DuExFQQh8= + +C:Q1VVfxM3uSO0X38HWpj1LN0E61fxo= +P:musl-utils +V:1.2.3-r0 +A:x86_64 +S:36938 +I:135168 +T:the musl c library (libc) implementation +U:https://musl.libc.org/ +L:MIT BSD GPL2+ +o:musl +m:Timo Teräs +t:1649396308 +c:ee13d43a53938d8a04ba787b9423f3270a3c14a7 +D:scanelf so:libc.musl-x86_64.so.1 +p:cmd:getconf=1.2.3-r0 cmd:getent=1.2.3-r0 cmd:iconv=1.2.3-r0 cmd:ldconfig=1.2.3-r0 cmd:ldd=1.2.3-r0 +r:libiconv +F:sbin +R:ldconfig +a:0:0:755 +Z:Q1Kja2+POZKxEkUOZqwSjC6kmaED4= +F:usr +F:usr/bin +R:getconf +a:0:0:755 +Z:Q1hRQA0bFX/Ywt3mbD6NpV9BIbPrU= +R:getent +a:0:0:755 +Z:Q1khbUz6GBU8iiQ3oV6Ln2hlXf4/0= +R:iconv +a:0:0:755 +Z:Q1H1QpYQDkdYIK2LLGv3m6qjpLyAY= +R:ldd +a:0:0:755 +Z:Q1yFAhGggmL7ERgbIA7KQxyTzf3ks= + +C:Q1O4GFJRvHz95tPjO84qpEvkNVwDw= +P:libc-utils +V:0.7.2-r3 +A:x86_64 +S:1480 +I:4096 +T:Meta package to pull in correct libc +U:https://alpinelinux.org +L:BSD-2-Clause AND BSD-3-Clause +o:libc-dev +m:Natanael Copa +t:1585632275 +c:60424133be2e79bbfeff3d58147a22886f817ce2 +D:musl-utils + diff --git a/test/integration/encode_decode_cycle_test.go b/test/integration/encode_decode_cycle_test.go index 110ae5de75c..8f47e10ce8c 100644 --- a/test/integration/encode_decode_cycle_test.go +++ b/test/integration/encode_decode_cycle_test.go @@ -36,7 +36,7 @@ func TestEncodeDecodeEncodeCycleComparison(t *testing.T) { { formatOption: syftjson.ID, redactor: func(in []byte) []byte { - in = regexp.MustCompile("\"(id|parent)\": \"[^\"]+\",").ReplaceAll(in, []byte{}) + // no redactions necessary return in }, json: true, @@ -44,7 +44,9 @@ func TestEncodeDecodeEncodeCycleComparison(t *testing.T) { { formatOption: cyclonedxjson.ID, redactor: func(in []byte) []byte { - in = regexp.MustCompile("\"(timestamp|serialNumber|bom-ref)\": \"[^\"]+\",").ReplaceAll(in, []byte{}) + // unstable values + in = regexp.MustCompile(`"(timestamp|serialNumber|bom-ref)": "[^"]+",`).ReplaceAll(in, []byte{}) + return in }, json: true, @@ -52,8 +54,10 @@ func TestEncodeDecodeEncodeCycleComparison(t *testing.T) { { formatOption: cyclonedxxml.ID, redactor: func(in []byte) []byte { - in = regexp.MustCompile("(serialNumber|bom-ref)=\"[^\"]+\"").ReplaceAll(in, []byte{}) - in = regexp.MustCompile("[^<]+").ReplaceAll(in, []byte{}) + // unstable values + in = regexp.MustCompile(`(serialNumber|bom-ref)="[^"]+"`).ReplaceAll(in, []byte{}) + in = regexp.MustCompile(`[^<]+`).ReplaceAll(in, []byte{}) + return in }, },