diff --git a/.golangci.yaml b/.golangci.yaml index 3fefa111c98..3cd28961511 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -1,5 +1,6 @@ issues: max-same-issues: 25 + uniq-by-line: false # TODO: enable this when we have coverage on docstring comments # # The list of ids of default excludes to include or disable. @@ -60,8 +61,6 @@ linters-settings: gosec: excludes: - G115 -output: - uniq-by-line: false run: timeout: 10m tests: false diff --git a/internal/constants.go b/internal/constants.go index 4dd27cf7953..469f075c89c 100644 --- a/internal/constants.go +++ b/internal/constants.go @@ -3,5 +3,5 @@ package internal 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 = "16.0.18" + JSONSchemaVersion = "16.0.19" ) diff --git a/internal/task/package_tasks.go b/internal/task/package_tasks.go index 431c77590f4..c9a4767eb8c 100644 --- a/internal/task/package_tasks.go +++ b/internal/task/package_tasks.go @@ -114,6 +114,7 @@ func DefaultPackageTaskFactories() PackageTaskFactories { newSimplePackageTaskFactory(ocaml.NewOpamPackageManagerCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, "ocaml", "opam"), // language-specific package for both image and directory scans (but not necessarily declared) //////////////////////////////////////// + newSimplePackageTaskFactory(dotnet.NewDotnetPackagesLockCataloger, pkgcataloging.DeclaredTag, pkgcataloging.ImageTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, "dotnet", "c#"), newSimplePackageTaskFactory(dotnet.NewDotnetPortableExecutableCataloger, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "dotnet", "c#", "binary"), newSimplePackageTaskFactory(python.NewInstalledPackageCataloger, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "python"), newPackageTaskFactory( diff --git a/schema/json/schema-16.0.19.json b/schema/json/schema-16.0.19.json new file mode 100644 index 00000000000..590b5e23731 --- /dev/null +++ b/schema/json/schema-16.0.19.json @@ -0,0 +1,2753 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "anchore.io/schema/syft/json/16.0.19/document", + "$ref": "#/$defs/Document", + "$defs": { + "AlpmDbEntry": { + "properties": { + "basepackage": { + "type": "string" + }, + "package": { + "type": "string" + }, + "version": { + "type": "string" + }, + "description": { + "type": "string" + }, + "architecture": { + "type": "string" + }, + "size": { + "type": "integer" + }, + "packager": { + "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" + }, + "provides": { + "items": { + "type": "string" + }, + "type": "array" + }, + "depends": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "basepackage", + "package", + "version", + "description", + "architecture", + "size", + "packager", + "url", + "validation", + "reason", + "files", + "backup" + ] + }, + "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" + }, + "ApkDbEntry": { + "properties": { + "package": { + "type": "string" + }, + "originPackage": { + "type": "string" + }, + "maintainer": { + "type": "string" + }, + "version": { + "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", + "architecture", + "url", + "description", + "size", + "installedSize", + "pullDependencies", + "provides", + "pullChecksum", + "gitCommitOfApkPort", + "files" + ] + }, + "ApkFileRecord": { + "properties": { + "path": { + "type": "string" + }, + "ownerUid": { + "type": "string" + }, + "ownerGid": { + "type": "string" + }, + "permissions": { + "type": "string" + }, + "digest": { + "$ref": "#/$defs/Digest" + } + }, + "type": "object", + "required": [ + "path" + ] + }, + "BinarySignature": { + "properties": { + "matches": { + "items": { + "$ref": "#/$defs/ClassifierMatch" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "matches" + ] + }, + "CConanFileEntry": { + "properties": { + "ref": { + "type": "string" + } + }, + "type": "object", + "required": [ + "ref" + ] + }, + "CConanInfoEntry": { + "properties": { + "ref": { + "type": "string" + }, + "package_id": { + "type": "string" + } + }, + "type": "object", + "required": [ + "ref" + ] + }, + "CConanLockEntry": { + "properties": { + "ref": { + "type": "string" + }, + "package_id": { + "type": "string" + }, + "prev": { + "type": "string" + }, + "requires": { + "items": { + "type": "string" + }, + "type": "array" + }, + "build_requires": { + "items": { + "type": "string" + }, + "type": "array" + }, + "py_requires": { + "items": { + "type": "string" + }, + "type": "array" + }, + "options": { + "$ref": "#/$defs/KeyValues" + }, + "path": { + "type": "string" + }, + "context": { + "type": "string" + } + }, + "type": "object", + "required": [ + "ref" + ] + }, + "CConanLockV2Entry": { + "properties": { + "ref": { + "type": "string" + }, + "packageID": { + "type": "string" + }, + "username": { + "type": "string" + }, + "channel": { + "type": "string" + }, + "recipeRevision": { + "type": "string" + }, + "packageRevision": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + }, + "type": "object", + "required": [ + "ref" + ] + }, + "CPE": { + "properties": { + "cpe": { + "type": "string" + }, + "source": { + "type": "string" + } + }, + "type": "object", + "required": [ + "cpe" + ] + }, + "ClassifierMatch": { + "properties": { + "classifier": { + "type": "string" + }, + "location": { + "$ref": "#/$defs/Location" + } + }, + "type": "object", + "required": [ + "classifier", + "location" + ] + }, + "CocoaPodfileLockEntry": { + "properties": { + "checksum": { + "type": "string" + } + }, + "type": "object", + "required": [ + "checksum" + ] + }, + "Coordinates": { + "properties": { + "path": { + "type": "string" + }, + "layerID": { + "type": "string" + } + }, + "type": "object", + "required": [ + "path" + ] + }, + "DartPubspecLockEntry": { + "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" + }, + "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" + ] + }, + "DotnetDepsEntry": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "path": { + "type": "string" + }, + "sha512": { + "type": "string" + }, + "hashPath": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "version", + "path", + "sha512", + "hashPath" + ] + }, + "DotnetPackagesLockEntry": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "contentHash": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "version", + "contentHash", + "type" + ] + }, + "DotnetPortableExecutableEntry": { + "properties": { + "assemblyVersion": { + "type": "string" + }, + "legalCopyright": { + "type": "string" + }, + "comments": { + "type": "string" + }, + "internalName": { + "type": "string" + }, + "companyName": { + "type": "string" + }, + "productName": { + "type": "string" + }, + "productVersion": { + "type": "string" + } + }, + "type": "object", + "required": [ + "assemblyVersion", + "legalCopyright", + "companyName", + "productName", + "productVersion" + ] + }, + "DpkgDbEntry": { + "properties": { + "package": { + "type": "string" + }, + "source": { + "type": "string" + }, + "version": { + "type": "string" + }, + "sourceVersion": { + "type": "string" + }, + "architecture": { + "type": "string" + }, + "maintainer": { + "type": "string" + }, + "installedSize": { + "type": "integer" + }, + "provides": { + "items": { + "type": "string" + }, + "type": "array" + }, + "depends": { + "items": { + "type": "string" + }, + "type": "array" + }, + "preDepends": { + "items": { + "type": "string" + }, + "type": "array" + }, + "files": { + "items": { + "$ref": "#/$defs/DpkgFileRecord" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "package", + "source", + "version", + "sourceVersion", + "architecture", + "maintainer", + "installedSize", + "files" + ] + }, + "DpkgFileRecord": { + "properties": { + "path": { + "type": "string" + }, + "digest": { + "$ref": "#/$defs/Digest" + }, + "isConfigFile": { + "type": "boolean" + } + }, + "type": "object", + "required": [ + "path", + "isConfigFile" + ] + }, + "ELFSecurityFeatures": { + "properties": { + "symbolTableStripped": { + "type": "boolean" + }, + "stackCanary": { + "type": "boolean" + }, + "nx": { + "type": "boolean" + }, + "relRO": { + "type": "string" + }, + "pie": { + "type": "boolean" + }, + "dso": { + "type": "boolean" + }, + "safeStack": { + "type": "boolean" + }, + "cfi": { + "type": "boolean" + }, + "fortify": { + "type": "boolean" + } + }, + "type": "object", + "required": [ + "symbolTableStripped", + "nx", + "relRO", + "pie", + "dso" + ] + }, + "ElfBinaryPackageNoteJsonPayload": { + "properties": { + "type": { + "type": "string" + }, + "architecture": { + "type": "string" + }, + "osCPE": { + "type": "string" + }, + "os": { + "type": "string" + }, + "osVersion": { + "type": "string" + }, + "system": { + "type": "string" + }, + "vendor": { + "type": "string" + }, + "sourceRepo": { + "type": "string" + }, + "commit": { + "type": "string" + } + }, + "type": "object" + }, + "ElixirMixLockEntry": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "pkgHash": { + "type": "string" + }, + "pkgHashExt": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "version", + "pkgHash", + "pkgHashExt" + ] + }, + "ErlangRebarLockEntry": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "pkgHash": { + "type": "string" + }, + "pkgHashExt": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "version", + "pkgHash", + "pkgHashExt" + ] + }, + "Executable": { + "properties": { + "format": { + "type": "string" + }, + "hasExports": { + "type": "boolean" + }, + "hasEntrypoint": { + "type": "boolean" + }, + "importedLibraries": { + "items": { + "type": "string" + }, + "type": "array" + }, + "elfSecurityFeatures": { + "$ref": "#/$defs/ELFSecurityFeatures" + } + }, + "type": "object", + "required": [ + "format", + "hasExports", + "hasEntrypoint", + "importedLibraries" + ] + }, + "File": { + "properties": { + "id": { + "type": "string" + }, + "location": { + "$ref": "#/$defs/Coordinates" + }, + "metadata": { + "$ref": "#/$defs/FileMetadataEntry" + }, + "contents": { + "type": "string" + }, + "digests": { + "items": { + "$ref": "#/$defs/Digest" + }, + "type": "array" + }, + "licenses": { + "items": { + "$ref": "#/$defs/FileLicense" + }, + "type": "array" + }, + "executable": { + "$ref": "#/$defs/Executable" + }, + "unknowns": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "id", + "location" + ] + }, + "FileLicense": { + "properties": { + "value": { + "type": "string" + }, + "spdxExpression": { + "type": "string" + }, + "type": { + "type": "string" + }, + "evidence": { + "$ref": "#/$defs/FileLicenseEvidence" + } + }, + "type": "object", + "required": [ + "value", + "spdxExpression", + "type" + ] + }, + "FileLicenseEvidence": { + "properties": { + "confidence": { + "type": "integer" + }, + "offset": { + "type": "integer" + }, + "extent": { + "type": "integer" + } + }, + "type": "object", + "required": [ + "confidence", + "offset", + "extent" + ] + }, + "FileMetadataEntry": { + "properties": { + "mode": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "linkDestination": { + "type": "string" + }, + "userID": { + "type": "integer" + }, + "groupID": { + "type": "integer" + }, + "mimeType": { + "type": "string" + }, + "size": { + "type": "integer" + } + }, + "type": "object", + "required": [ + "mode", + "type", + "userID", + "groupID", + "mimeType", + "size" + ] + }, + "GoModuleBuildinfoEntry": { + "properties": { + "goBuildSettings": { + "$ref": "#/$defs/KeyValues" + }, + "goCompiledVersion": { + "type": "string" + }, + "architecture": { + "type": "string" + }, + "h1Digest": { + "type": "string" + }, + "mainModule": { + "type": "string" + }, + "goCryptoSettings": { + "items": { + "type": "string" + }, + "type": "array" + }, + "goExperiments": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "goCompiledVersion", + "architecture" + ] + }, + "GoModuleEntry": { + "properties": { + "h1Digest": { + "type": "string" + } + }, + "type": "object" + }, + "HaskellHackageStackEntry": { + "properties": { + "pkgHash": { + "type": "string" + } + }, + "type": "object" + }, + "HaskellHackageStackLockEntry": { + "properties": { + "pkgHash": { + "type": "string" + }, + "snapshotURL": { + "type": "string" + } + }, + "type": "object" + }, + "IDLikes": { + "items": { + "type": "string" + }, + "type": "array" + }, + "JavaArchive": { + "properties": { + "virtualPath": { + "type": "string" + }, + "manifest": { + "$ref": "#/$defs/JavaManifest" + }, + "pomProperties": { + "$ref": "#/$defs/JavaPomProperties" + }, + "pomProject": { + "$ref": "#/$defs/JavaPomProject" + }, + "digest": { + "items": { + "$ref": "#/$defs/Digest" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "virtualPath" + ] + }, + "JavaJvmInstallation": { + "properties": { + "release": { + "$ref": "#/$defs/JavaVMRelease" + }, + "files": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "release", + "files" + ] + }, + "JavaManifest": { + "properties": { + "main": { + "$ref": "#/$defs/KeyValues" + }, + "sections": { + "items": { + "$ref": "#/$defs/KeyValues" + }, + "type": "array" + } + }, + "type": "object" + }, + "JavaPomParent": { + "properties": { + "groupId": { + "type": "string" + }, + "artifactId": { + "type": "string" + }, + "version": { + "type": "string" + } + }, + "type": "object", + "required": [ + "groupId", + "artifactId", + "version" + ] + }, + "JavaPomProject": { + "properties": { + "path": { + "type": "string" + }, + "parent": { + "$ref": "#/$defs/JavaPomParent" + }, + "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" + ] + }, + "JavaPomProperties": { + "properties": { + "path": { + "type": "string" + }, + "name": { + "type": "string" + }, + "groupId": { + "type": "string" + }, + "artifactId": { + "type": "string" + }, + "version": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "extraFields": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object", + "required": [ + "path", + "name", + "groupId", + "artifactId", + "version" + ] + }, + "JavaVMRelease": { + "properties": { + "implementor": { + "type": "string" + }, + "implementorVersion": { + "type": "string" + }, + "javaRuntimeVersion": { + "type": "string" + }, + "javaVersion": { + "type": "string" + }, + "javaVersionDate": { + "type": "string" + }, + "libc": { + "type": "string" + }, + "modules": { + "items": { + "type": "string" + }, + "type": "array" + }, + "osArch": { + "type": "string" + }, + "osName": { + "type": "string" + }, + "osVersion": { + "type": "string" + }, + "source": { + "type": "string" + }, + "buildSource": { + "type": "string" + }, + "buildSourceRepo": { + "type": "string" + }, + "sourceRepo": { + "type": "string" + }, + "fullVersion": { + "type": "string" + }, + "semanticVersion": { + "type": "string" + }, + "buildInfo": { + "type": "string" + }, + "jvmVariant": { + "type": "string" + }, + "jvmVersion": { + "type": "string" + }, + "imageType": { + "type": "string" + }, + "buildType": { + "type": "string" + } + }, + "type": "object" + }, + "JavascriptNpmPackage": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "author": { + "type": "string" + }, + "homepage": { + "type": "string" + }, + "description": { + "type": "string" + }, + "url": { + "type": "string" + }, + "private": { + "type": "boolean" + } + }, + "type": "object", + "required": [ + "name", + "version", + "author", + "homepage", + "description", + "url", + "private" + ] + }, + "JavascriptNpmPackageLockEntry": { + "properties": { + "resolved": { + "type": "string" + }, + "integrity": { + "type": "string" + } + }, + "type": "object", + "required": [ + "resolved", + "integrity" + ] + }, + "JavascriptYarnLockEntry": { + "properties": { + "resolved": { + "type": "string" + }, + "integrity": { + "type": "string" + } + }, + "type": "object", + "required": [ + "resolved", + "integrity" + ] + }, + "KeyValue": { + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object", + "required": [ + "key", + "value" + ] + }, + "KeyValues": { + "items": { + "$ref": "#/$defs/KeyValue" + }, + "type": "array" + }, + "License": { + "properties": { + "value": { + "type": "string" + }, + "spdxExpression": { + "type": "string" + }, + "type": { + "type": "string" + }, + "urls": { + "items": { + "type": "string" + }, + "type": "array" + }, + "locations": { + "items": { + "$ref": "#/$defs/Location" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "value", + "spdxExpression", + "type", + "urls", + "locations" + ] + }, + "LinuxKernelArchive": { + "properties": { + "name": { + "type": "string" + }, + "architecture": { + "type": "string" + }, + "version": { + "type": "string" + }, + "extendedVersion": { + "type": "string" + }, + "buildTime": { + "type": "string" + }, + "author": { + "type": "string" + }, + "format": { + "type": "string" + }, + "rwRootFS": { + "type": "boolean" + }, + "swapDevice": { + "type": "integer" + }, + "rootDevice": { + "type": "integer" + }, + "videoMode": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "architecture", + "version" + ] + }, + "LinuxKernelModule": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "sourceVersion": { + "type": "string" + }, + "path": { + "type": "string" + }, + "description": { + "type": "string" + }, + "author": { + "type": "string" + }, + "license": { + "type": "string" + }, + "kernelVersion": { + "type": "string" + }, + "versionMagic": { + "type": "string" + }, + "parameters": { + "patternProperties": { + ".*": { + "$ref": "#/$defs/LinuxKernelModuleParameter" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "LinuxKernelModuleParameter": { + "properties": { + "type": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "type": "object" + }, + "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" + }, + "supportEnd": { + "type": "string" + } + }, + "type": "object" + }, + "Location": { + "properties": { + "path": { + "type": "string" + }, + "layerID": { + "type": "string" + }, + "accessPath": { + "type": "string" + }, + "annotations": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object", + "required": [ + "path", + "accessPath" + ] + }, + "LuarocksPackage": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "license": { + "type": "string" + }, + "homepage": { + "type": "string" + }, + "description": { + "type": "string" + }, + "url": { + "type": "string" + }, + "dependencies": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object", + "required": [ + "name", + "version", + "license", + "homepage", + "description", + "url", + "dependencies" + ] + }, + "MicrosoftKbPatch": { + "properties": { + "product_id": { + "type": "string" + }, + "kb": { + "type": "string" + } + }, + "type": "object", + "required": [ + "product_id", + "kb" + ] + }, + "NixStoreEntry": { + "properties": { + "outputHash": { + "type": "string" + }, + "output": { + "type": "string" + }, + "files": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "outputHash", + "files" + ] + }, + "OpamPackage": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "licenses": { + "items": { + "type": "string" + }, + "type": "array" + }, + "url": { + "type": "string" + }, + "checksum": { + "items": { + "type": "string" + }, + "type": "array" + }, + "homepage": { + "type": "string" + }, + "dependencies": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "name", + "version", + "licenses", + "url", + "checksum", + "homepage", + "dependencies" + ] + }, + "Package": { + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "type": { + "type": "string" + }, + "foundBy": { + "type": "string" + }, + "locations": { + "items": { + "$ref": "#/$defs/Location" + }, + "type": "array" + }, + "licenses": { + "$ref": "#/$defs/licenses" + }, + "language": { + "type": "string" + }, + "cpes": { + "$ref": "#/$defs/cpes" + }, + "purl": { + "type": "string" + }, + "metadataType": { + "type": "string" + }, + "metadata": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/AlpmDbEntry" + }, + { + "$ref": "#/$defs/ApkDbEntry" + }, + { + "$ref": "#/$defs/BinarySignature" + }, + { + "$ref": "#/$defs/CConanFileEntry" + }, + { + "$ref": "#/$defs/CConanInfoEntry" + }, + { + "$ref": "#/$defs/CConanLockEntry" + }, + { + "$ref": "#/$defs/CConanLockV2Entry" + }, + { + "$ref": "#/$defs/CocoaPodfileLockEntry" + }, + { + "$ref": "#/$defs/DartPubspecLockEntry" + }, + { + "$ref": "#/$defs/DotnetDepsEntry" + }, + { + "$ref": "#/$defs/DotnetPackagesLockEntry" + }, + { + "$ref": "#/$defs/DotnetPortableExecutableEntry" + }, + { + "$ref": "#/$defs/DpkgDbEntry" + }, + { + "$ref": "#/$defs/ElfBinaryPackageNoteJsonPayload" + }, + { + "$ref": "#/$defs/ElixirMixLockEntry" + }, + { + "$ref": "#/$defs/ErlangRebarLockEntry" + }, + { + "$ref": "#/$defs/GoModuleBuildinfoEntry" + }, + { + "$ref": "#/$defs/GoModuleEntry" + }, + { + "$ref": "#/$defs/HaskellHackageStackEntry" + }, + { + "$ref": "#/$defs/HaskellHackageStackLockEntry" + }, + { + "$ref": "#/$defs/JavaArchive" + }, + { + "$ref": "#/$defs/JavaJvmInstallation" + }, + { + "$ref": "#/$defs/JavascriptNpmPackage" + }, + { + "$ref": "#/$defs/JavascriptNpmPackageLockEntry" + }, + { + "$ref": "#/$defs/JavascriptYarnLockEntry" + }, + { + "$ref": "#/$defs/LinuxKernelArchive" + }, + { + "$ref": "#/$defs/LinuxKernelModule" + }, + { + "$ref": "#/$defs/LuarocksPackage" + }, + { + "$ref": "#/$defs/MicrosoftKbPatch" + }, + { + "$ref": "#/$defs/NixStoreEntry" + }, + { + "$ref": "#/$defs/OpamPackage" + }, + { + "$ref": "#/$defs/PhpComposerInstalledEntry" + }, + { + "$ref": "#/$defs/PhpComposerLockEntry" + }, + { + "$ref": "#/$defs/PhpPeclEntry" + }, + { + "$ref": "#/$defs/PortageDbEntry" + }, + { + "$ref": "#/$defs/PythonPackage" + }, + { + "$ref": "#/$defs/PythonPipRequirementsEntry" + }, + { + "$ref": "#/$defs/PythonPipfileLockEntry" + }, + { + "$ref": "#/$defs/PythonPoetryLockEntry" + }, + { + "$ref": "#/$defs/RDescription" + }, + { + "$ref": "#/$defs/RpmArchive" + }, + { + "$ref": "#/$defs/RpmDbEntry" + }, + { + "$ref": "#/$defs/RubyGemspec" + }, + { + "$ref": "#/$defs/RustCargoAuditEntry" + }, + { + "$ref": "#/$defs/RustCargoLockEntry" + }, + { + "$ref": "#/$defs/SwiftPackageManagerLockEntry" + }, + { + "$ref": "#/$defs/SwiplpackPackage" + }, + { + "$ref": "#/$defs/WordpressPluginEntry" + } + ] + } + }, + "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" + ] + }, + "PhpComposerInstalledEntry": { + "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" + }, + "license": { + "items": { + "type": "string" + }, + "type": "array" + }, + "type": { + "type": "string" + }, + "notification-url": { + "type": "string" + }, + "bin": { + "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" + ] + }, + "PhpComposerLockEntry": { + "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" + }, + "license": { + "items": { + "type": "string" + }, + "type": "array" + }, + "type": { + "type": "string" + }, + "notification-url": { + "type": "string" + }, + "bin": { + "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" + ] + }, + "PhpPeclEntry": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "license": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "name", + "version" + ] + }, + "PortageDbEntry": { + "properties": { + "installedSize": { + "type": "integer" + }, + "files": { + "items": { + "$ref": "#/$defs/PortageFileRecord" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "installedSize", + "files" + ] + }, + "PortageFileRecord": { + "properties": { + "path": { + "type": "string" + }, + "digest": { + "$ref": "#/$defs/Digest" + } + }, + "type": "object", + "required": [ + "path" + ] + }, + "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" + ] + }, + "PythonPackage": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "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" + }, + "requiresPython": { + "type": "string" + }, + "requiresDist": { + "items": { + "type": "string" + }, + "type": "array" + }, + "providesExtra": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "name", + "version", + "author", + "authorEmail", + "platform", + "sitePackagesRootPath" + ] + }, + "PythonPipRequirementsEntry": { + "properties": { + "name": { + "type": "string" + }, + "extras": { + "items": { + "type": "string" + }, + "type": "array" + }, + "versionConstraint": { + "type": "string" + }, + "url": { + "type": "string" + }, + "markers": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "versionConstraint" + ] + }, + "PythonPipfileLockEntry": { + "properties": { + "hashes": { + "items": { + "type": "string" + }, + "type": "array" + }, + "index": { + "type": "string" + } + }, + "type": "object", + "required": [ + "hashes", + "index" + ] + }, + "PythonPoetryLockDependencyEntry": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "optional": { + "type": "boolean" + }, + "markers": { + "type": "string" + }, + "extras": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "name", + "version", + "optional" + ] + }, + "PythonPoetryLockEntry": { + "properties": { + "index": { + "type": "string" + }, + "dependencies": { + "items": { + "$ref": "#/$defs/PythonPoetryLockDependencyEntry" + }, + "type": "array" + }, + "extras": { + "items": { + "$ref": "#/$defs/PythonPoetryLockExtraEntry" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "index", + "dependencies" + ] + }, + "PythonPoetryLockExtraEntry": { + "properties": { + "name": { + "type": "string" + }, + "dependencies": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "name", + "dependencies" + ] + }, + "RDescription": { + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "author": { + "type": "string" + }, + "maintainer": { + "type": "string" + }, + "url": { + "items": { + "type": "string" + }, + "type": "array" + }, + "repository": { + "type": "string" + }, + "built": { + "type": "string" + }, + "needsCompilation": { + "type": "boolean" + }, + "imports": { + "items": { + "type": "string" + }, + "type": "array" + }, + "depends": { + "items": { + "type": "string" + }, + "type": "array" + }, + "suggests": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "Relationship": { + "properties": { + "parent": { + "type": "string" + }, + "child": { + "type": "string" + }, + "type": { + "type": "string" + }, + "metadata": true + }, + "type": "object", + "required": [ + "parent", + "child", + "type" + ] + }, + "RpmArchive": { + "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" + }, + "vendor": { + "type": "string" + }, + "modularityLabel": { + "type": "string" + }, + "provides": { + "items": { + "type": "string" + }, + "type": "array" + }, + "requires": { + "items": { + "type": "string" + }, + "type": "array" + }, + "files": { + "items": { + "$ref": "#/$defs/RpmFileRecord" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "name", + "version", + "epoch", + "architecture", + "release", + "sourceRpm", + "size", + "vendor", + "files" + ] + }, + "RpmDbEntry": { + "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" + }, + "vendor": { + "type": "string" + }, + "modularityLabel": { + "type": "string" + }, + "provides": { + "items": { + "type": "string" + }, + "type": "array" + }, + "requires": { + "items": { + "type": "string" + }, + "type": "array" + }, + "files": { + "items": { + "$ref": "#/$defs/RpmFileRecord" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "name", + "version", + "epoch", + "architecture", + "release", + "sourceRpm", + "size", + "vendor", + "files" + ] + }, + "RpmFileRecord": { + "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" + ] + }, + "RubyGemspec": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "files": { + "items": { + "type": "string" + }, + "type": "array" + }, + "authors": { + "items": { + "type": "string" + }, + "type": "array" + }, + "homepage": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "version" + ] + }, + "RustCargoAuditEntry": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "source": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "version", + "source" + ] + }, + "RustCargoLockEntry": { + "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" + ] + }, + "Schema": { + "properties": { + "version": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "type": "object", + "required": [ + "version", + "url" + ] + }, + "Source": { + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "type": { + "type": "string" + }, + "metadata": true + }, + "type": "object", + "required": [ + "id", + "name", + "version", + "type", + "metadata" + ] + }, + "SwiftPackageManagerLockEntry": { + "properties": { + "revision": { + "type": "string" + } + }, + "type": "object", + "required": [ + "revision" + ] + }, + "SwiplpackPackage": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "author": { + "type": "string" + }, + "authorEmail": { + "type": "string" + }, + "packager": { + "type": "string" + }, + "packagerEmail": { + "type": "string" + }, + "homepage": { + "type": "string" + }, + "dependencies": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "name", + "version", + "author", + "authorEmail", + "packager", + "packagerEmail", + "homepage", + "dependencies" + ] + }, + "WordpressPluginEntry": { + "properties": { + "pluginInstallDirectory": { + "type": "string" + }, + "author": { + "type": "string" + }, + "authorUri": { + "type": "string" + } + }, + "type": "object", + "required": [ + "pluginInstallDirectory" + ] + }, + "cpes": { + "items": { + "$ref": "#/$defs/CPE" + }, + "type": "array" + }, + "licenses": { + "items": { + "$ref": "#/$defs/License" + }, + "type": "array" + } + } +} diff --git a/schema/json/schema-latest.json b/schema/json/schema-latest.json index 936582e2d22..590b5e23731 100644 --- a/schema/json/schema-latest.json +++ b/schema/json/schema-latest.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "anchore.io/schema/syft/json/16.0.18/document", + "$id": "anchore.io/schema/syft/json/16.0.19/document", "$ref": "#/$defs/Document", "$defs": { "AlpmDbEntry": { @@ -492,6 +492,29 @@ "hashPath" ] }, + "DotnetPackagesLockEntry": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "contentHash": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "version", + "contentHash", + "type" + ] + }, "DotnetPortableExecutableEntry": { "properties": { "assemblyVersion": { @@ -1648,6 +1671,9 @@ { "$ref": "#/$defs/DotnetDepsEntry" }, + { + "$ref": "#/$defs/DotnetPackagesLockEntry" + }, { "$ref": "#/$defs/DotnetPortableExecutableEntry" }, diff --git a/syft/format/internal/spdxutil/helpers/originator_supplier_test.go b/syft/format/internal/spdxutil/helpers/originator_supplier_test.go index 4ed8fc2ca7f..2504deb4fd5 100644 --- a/syft/format/internal/spdxutil/helpers/originator_supplier_test.go +++ b/syft/format/internal/spdxutil/helpers/originator_supplier_test.go @@ -19,6 +19,7 @@ func Test_OriginatorSupplier(t *testing.T) { pkg.ConaninfoEntry{}, pkg.DartPubspecLockEntry{}, pkg.DotnetDepsEntry{}, + pkg.DotnetPackagesLockEntry{}, pkg.ELFBinaryPackageNoteJSONPayload{}, pkg.ElixirMixLockEntry{}, pkg.ErlangRebarLockEntry{}, diff --git a/syft/internal/packagemetadata/generated.go b/syft/internal/packagemetadata/generated.go index d22cfcd77b8..4ab682de2fd 100644 --- a/syft/internal/packagemetadata/generated.go +++ b/syft/internal/packagemetadata/generated.go @@ -17,6 +17,7 @@ func AllTypes() []any { pkg.ConaninfoEntry{}, pkg.DartPubspecLockEntry{}, pkg.DotnetDepsEntry{}, + pkg.DotnetPackagesLockEntry{}, pkg.DotnetPortableExecutableEntry{}, pkg.DpkgDBEntry{}, pkg.ELFBinaryPackageNoteJSONPayload{}, diff --git a/syft/internal/packagemetadata/names.go b/syft/internal/packagemetadata/names.go index b382dceebe7..1650b3a1104 100644 --- a/syft/internal/packagemetadata/names.go +++ b/syft/internal/packagemetadata/names.go @@ -109,6 +109,7 @@ var jsonTypes = makeJSONTypes( jsonNamesWithoutLookup(pkg.RustBinaryAuditEntry{}, "rust-cargo-audit-entry", "RustCargoPackageMetadata"), // the legacy value is split into two types, where the other is preferred jsonNames(pkg.WordpressPluginEntry{}, "wordpress-plugin-entry", "WordpressMetadata"), jsonNames(pkg.LuaRocksPackage{}, "luarocks-package"), + jsonNames(pkg.DotnetPackagesLockEntry{}, "dotnet-packages-lock-entry"), ) func expandLegacyNameVariants(names ...string) []string { diff --git a/syft/pkg/cataloger/dotnet/cataloger.go b/syft/pkg/cataloger/dotnet/cataloger.go index 74ad55cfb99..2257e3d860a 100644 --- a/syft/pkg/cataloger/dotnet/cataloger.go +++ b/syft/pkg/cataloger/dotnet/cataloger.go @@ -19,3 +19,7 @@ func NewDotnetPortableExecutableCataloger() pkg.Cataloger { return generic.NewCataloger("dotnet-portable-executable-cataloger"). WithParserByGlobs(parseDotnetPortableExecutable, "**/*.dll", "**/*.exe") } + +func NewDotnetPackagesLockCataloger() pkg.Cataloger { + return generic.NewCataloger("dotnet-packages-lock-cataloger").WithParserByGlobs(parseDotnetPackagesLock, "**/packages.lock.json") +} diff --git a/syft/pkg/cataloger/dotnet/parse_dotnet_packages_lock.go b/syft/pkg/cataloger/dotnet/parse_dotnet_packages_lock.go new file mode 100644 index 00000000000..d686e02445a --- /dev/null +++ b/syft/pkg/cataloger/dotnet/parse_dotnet_packages_lock.go @@ -0,0 +1,159 @@ +package dotnet + +import ( + "context" + "encoding/json" + "fmt" + "slices" + "sort" + + "github.com/anchore/packageurl-go" + "github.com/anchore/syft/internal/log" + "github.com/anchore/syft/internal/relationship" + "github.com/anchore/syft/syft/artifact" + "github.com/anchore/syft/syft/file" + "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/pkg/cataloger/generic" +) + +var _ generic.Parser = parseDotnetPackagesLock + +type dotnetPackagesLock struct { + Version int `json:"version"` + Dependencies map[string]map[string]dotnetPackagesLockDep `json:"dependencies"` +} + +type dotnetPackagesLockDep struct { + Type string `json:"type"` + Requested string `json:"requested"` + Resolved string `json:"resolved"` + ContentHash string `json:"contentHash"` + Dependencies map[string]string `json:"dependencies,omitempty"` +} + +func parseDotnetPackagesLock(_ context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) { //nolint:funlen + var pkgs []pkg.Package + var pkgMap = make(map[string]pkg.Package) + var relationships []artifact.Relationship + + dec := json.NewDecoder(reader) + + // unmarshal file + var lockFile dotnetPackagesLock + if err := dec.Decode(&lockFile); err != nil { + return nil, nil, fmt.Errorf("failed to parse packages.lock.json file: %w", err) + } + + // collect all deps here + allDependencies := make(map[string]dotnetPackagesLockDep) + + var names []string + for _, dependencies := range lockFile.Dependencies { + for name, dep := range dependencies { + depNameVersion := createNameAndVersion(name, dep.Resolved) + + if slices.Contains(names, depNameVersion) { + continue + } + + names = append(names, depNameVersion) + allDependencies[depNameVersion] = dep + } + } + + // sort the names so that the order of the packages is deterministic + sort.Strings(names) + + // create artifact for each pkg + for _, nameVersion := range names { + name, _ := extractNameAndVersion(nameVersion) + + dep := allDependencies[nameVersion] + dotnetPkg := newDotnetPackagesLockPackage(name, dep, reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)) + if dotnetPkg != nil { + pkgs = append(pkgs, *dotnetPkg) + pkgMap[nameVersion] = *dotnetPkg + } + } + + // fill up relationships + for depNameVersion, dep := range allDependencies { + parentPkg, ok := pkgMap[depNameVersion] + if !ok { + log.Debug("package \"%s\" not found in map of all pacakges", depNameVersion) + continue + } + + for childDepName, childDepVersion := range dep.Dependencies { + childDepNameVersion := createNameAndVersion(childDepName, childDepVersion) + + // try and find pkg for dependency with exact name and version + childPkg, ok := pkgMap[childDepNameVersion] + if !ok { + // no exact match found, lets match on name only, lockfile will contain other version of pkg + cpkg, ok := findPkgByName(childDepName, pkgMap) + if !ok { + log.Debug("dependency \"%s\" of package \"%s\" not found in map of all packages", childDepNameVersion, depNameVersion) + continue + } + + childPkg = *cpkg + } + + rel := artifact.Relationship{ + From: parentPkg, + To: childPkg, + Type: artifact.DependencyOfRelationship, + } + relationships = append(relationships, rel) + } + } + + // sort the relationships for deterministic output + relationship.Sort(relationships) + + return pkgs, relationships, nil +} + +func newDotnetPackagesLockPackage(name string, dep dotnetPackagesLockDep, locations ...file.Location) *pkg.Package { + metadata := pkg.DotnetPackagesLockEntry{ + Name: name, + Version: dep.Resolved, + ContentHash: dep.ContentHash, + Type: dep.Type, + } + + return &pkg.Package{ + Name: name, + Version: dep.Resolved, + Type: pkg.DotnetPkg, + Metadata: metadata, + Locations: file.NewLocationSet(locations...), + Language: pkg.Dotnet, + PURL: packagesLockPackageURL(name, dep.Resolved), + } +} + +func packagesLockPackageURL(name, version string) string { + var qualifiers packageurl.Qualifiers + + return packageurl.NewPackageURL( + packageurl.TypeNuget, // See explanation in syft/pkg/cataloger/dotnet/package.go as to why this was chosen. + "", + name, + version, + qualifiers, + "", + ).ToString() +} + +func findPkgByName(pkgName string, pkgMap map[string]pkg.Package) (*pkg.Package, bool) { + for pkgNameVersion, pkg := range pkgMap { + name, _ := extractNameAndVersion(pkgNameVersion) + if name == pkgName { + return &pkg, true + } + } + + return nil, false +} diff --git a/syft/pkg/cataloger/dotnet/parse_dotnet_packages_lock_test.go b/syft/pkg/cataloger/dotnet/parse_dotnet_packages_lock_test.go new file mode 100644 index 00000000000..17ed88806e0 --- /dev/null +++ b/syft/pkg/cataloger/dotnet/parse_dotnet_packages_lock_test.go @@ -0,0 +1,199 @@ +package dotnet + +import ( + "testing" + + "github.com/anchore/syft/syft/artifact" + "github.com/anchore/syft/syft/file" + "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest" +) + +func Test_corruptDotnetPackagesLock(t *testing.T) { + pkgtest.NewCatalogTester(). + FromFile(t, "test-fixtures/glob-paths/src/packages.lock.json"). + WithError(). + TestParser(t, parseDotnetDeps) +} + +func TestParseDotnetPackagesLock(t *testing.T) { + fixture := "test-fixtures/packages.lock.json" + fixtureLocationSet := file.NewLocationSet(file.NewLocation(fixture)) + + autoMapperPkg := pkg.Package{ + Name: "AutoMapper", + Version: "13.0.1", + PURL: "pkg:nuget/AutoMapper@13.0.1", + Locations: fixtureLocationSet, + Language: pkg.Dotnet, + Type: pkg.DotnetPkg, + Metadata: pkg.DotnetPackagesLockEntry{ + Name: "AutoMapper", + Version: "13.0.1", + ContentHash: "/Fx1SbJ16qS7dU4i604Sle+U9VLX+WSNVJggk6MupKVkYvvBm4XqYaeFuf67diHefHKHs50uQIS2YEDFhPCakQ==", + Type: "Direct", + }, + } + + bootstrapPkg := pkg.Package{ + Name: "bootstrap", + Version: "5.0.0", + PURL: "pkg:nuget/bootstrap@5.0.0", + Locations: fixtureLocationSet, + Language: pkg.Dotnet, + Type: pkg.DotnetPkg, + Metadata: pkg.DotnetPackagesLockEntry{ + Name: "bootstrap", + Version: "5.0.0", + ContentHash: "NKQFzFwrfWOMjTwr+X/2iJyCveuAGF+fNzkxyB0YW45+InVhcE9PUxoL1a8Vmc/Lq9E/CQd4DjO8kU32P4w/Gg==", + Type: "Direct", + }, + } + + log4netPkg := pkg.Package{ + Name: "log4net", + Version: "2.0.5", + PURL: "pkg:nuget/log4net@2.0.5", + Locations: fixtureLocationSet, + Language: pkg.Dotnet, + Type: pkg.DotnetPkg, + Metadata: pkg.DotnetPackagesLockEntry{ + Name: "log4net", + Version: "2.0.5", + ContentHash: "AEqPZz+v+OikfnR2SqRVdQPnSaLq5y9Iz1CfRQZ9kTKPYCXHG6zYmDHb7wJotICpDLMr/JqokyjiqKAjUKp0ng==", + Type: "Direct", + }, + } + + log4net1Pkg := pkg.Package{ + Name: "log4net", + Version: "1.2.15", + PURL: "pkg:nuget/log4net@1.2.15", + Locations: fixtureLocationSet, + Language: pkg.Dotnet, + Type: pkg.DotnetPkg, + Metadata: pkg.DotnetPackagesLockEntry{ + Name: "log4net", + Version: "1.2.15", + ContentHash: "KPajjkU1rbF6uY2rnakbh36LB9z9FVcYlciyOi6C5SJ3AMNywxjCGxBTN/Hl5nQEinRLuWvHWPF8W7YHh9sONw==", + Type: "Direct", + }, + } + + dependencyInjectionAbstractionsPkg := pkg.Package{ + Name: "Microsoft.Extensions.DependencyInjection.Abstractions", + Version: "9.0.0", + PURL: "pkg:nuget/Microsoft.Extensions.DependencyInjection.Abstractions@9.0.0", + Locations: fixtureLocationSet, + Language: pkg.Dotnet, + Type: pkg.DotnetPkg, + Metadata: pkg.DotnetPackagesLockEntry{ + Name: "Microsoft.Extensions.DependencyInjection.Abstractions", + Version: "9.0.0", + ContentHash: "xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg==", + Type: "Transitive", + }, + } + + extensionOptionsPkg := pkg.Package{ + Name: "Microsoft.Extensions.Options", + Version: "9.0.0", + PURL: "pkg:nuget/Microsoft.Extensions.Options@9.0.0", + Locations: fixtureLocationSet, + Language: pkg.Dotnet, + Type: pkg.DotnetPkg, + Metadata: pkg.DotnetPackagesLockEntry{ + Name: "Microsoft.Extensions.Options", + Version: "9.0.0", + ContentHash: "dzXN0+V1AyjOe2xcJ86Qbo233KHuLEY0njf/P2Kw8SfJU+d45HNS2ctJdnEnrWbM9Ye2eFgaC5Mj9otRMU6IsQ==", + Type: "Transitive", + }, + } + + extensionPrimitivesPkg := pkg.Package{ + Name: "Microsoft.Extensions.Primitives", + Version: "9.0.0", + PURL: "pkg:nuget/Microsoft.Extensions.Primitives@9.0.0", + Locations: fixtureLocationSet, + Language: pkg.Dotnet, + Type: pkg.DotnetPkg, + Metadata: pkg.DotnetPackagesLockEntry{ + Name: "Microsoft.Extensions.Primitives", + Version: "9.0.0", + ContentHash: "9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ==", + Type: "Transitive", + }, + } + + compilerServicesUnsafePkg := pkg.Package{ + Name: "System.Runtime.CompilerServices.Unsafe", + Version: "9.0.0", + PURL: "pkg:nuget/System.Runtime.CompilerServices.Unsafe@9.0.0", + Locations: fixtureLocationSet, + Language: pkg.Dotnet, + Type: pkg.DotnetPkg, + Metadata: pkg.DotnetPackagesLockEntry{ + Name: "System.Runtime.CompilerServices.Unsafe", + Version: "9.0.0", + ContentHash: "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==", + Type: "Transitive", + }, + } + + microsoftLoggingPkg := pkg.Package{ + Name: "Microsoft.Extensions.Logging", + Version: "9.0.0", + PURL: "pkg:nuget/Microsoft.Extensions.Logging@9.0.0", + Locations: fixtureLocationSet, + Language: pkg.Dotnet, + Type: pkg.DotnetPkg, + Metadata: pkg.DotnetPackagesLockEntry{ + Name: "Microsoft.Extensions.Logging", + Version: "9.0.0", + ContentHash: "crjWyORoug0kK7RSNJBTeSE6VX8IQgLf3nUpTB9m62bPXp/tzbnOsnbe8TXEG0AASNaKZddnpHKw7fET8E++Pg==", + Type: "Direct", + }, + } + + expectedPkgs := []pkg.Package{ + autoMapperPkg, + compilerServicesUnsafePkg, + dependencyInjectionAbstractionsPkg, + microsoftLoggingPkg, + extensionOptionsPkg, + extensionPrimitivesPkg, + bootstrapPkg, + log4net1Pkg, + log4netPkg, + } + + expectedRelationships := []artifact.Relationship{ + { + From: autoMapperPkg, + To: extensionOptionsPkg, + Type: artifact.DependencyOfRelationship, + }, + { + From: extensionOptionsPkg, + To: dependencyInjectionAbstractionsPkg, + Type: artifact.DependencyOfRelationship, + }, + { + From: extensionOptionsPkg, + To: extensionPrimitivesPkg, + Type: artifact.DependencyOfRelationship, + }, + { + From: extensionPrimitivesPkg, + To: compilerServicesUnsafePkg, + Type: artifact.DependencyOfRelationship, + }, + { + From: microsoftLoggingPkg, + To: extensionOptionsPkg, + Type: artifact.DependencyOfRelationship, + }, + } + + pkgtest.TestFileParser(t, fixture, parseDotnetPackagesLock, expectedPkgs, expectedRelationships) +} diff --git a/syft/pkg/cataloger/dotnet/test-fixtures/glob-paths/src/packages.lock.json b/syft/pkg/cataloger/dotnet/test-fixtures/glob-paths/src/packages.lock.json new file mode 100644 index 00000000000..11d39bba539 --- /dev/null +++ b/syft/pkg/cataloger/dotnet/test-fixtures/glob-paths/src/packages.lock.json @@ -0,0 +1 @@ +"i am bogus" \ No newline at end of file diff --git a/syft/pkg/cataloger/dotnet/test-fixtures/packages.lock.json b/syft/pkg/cataloger/dotnet/test-fixtures/packages.lock.json new file mode 100644 index 00000000000..d8adc3adb9b --- /dev/null +++ b/syft/pkg/cataloger/dotnet/test-fixtures/packages.lock.json @@ -0,0 +1,78 @@ +{ + "version": 1, + "dependencies": { + "net8.0": { + "AutoMapper": { + "type": "Direct", + "requested": "[13.0.1, )", + "resolved": "13.0.1", + "contentHash": "/Fx1SbJ16qS7dU4i604Sle+U9VLX+WSNVJggk6MupKVkYvvBm4XqYaeFuf67diHefHKHs50uQIS2YEDFhPCakQ==", + "dependencies": { + "Microsoft.Extensions.Options": "6.0.0" + } + }, + "bootstrap": { + "type": "Direct", + "requested": "[5.0.0, )", + "resolved": "5.0.0", + "contentHash": "NKQFzFwrfWOMjTwr+X/2iJyCveuAGF+fNzkxyB0YW45+InVhcE9PUxoL1a8Vmc/Lq9E/CQd4DjO8kU32P4w/Gg==" + }, + "log4net": { + "type": "Direct", + "requested": "[2.0.5, )", + "resolved": "2.0.5", + "contentHash": "AEqPZz+v+OikfnR2SqRVdQPnSaLq5y9Iz1CfRQZ9kTKPYCXHG6zYmDHb7wJotICpDLMr/JqokyjiqKAjUKp0ng==" + }, + "Microsoft.Extensions.DependencyInjection.Abstractions": { + "type": "Transitive", + "resolved": "9.0.0", + "contentHash": "xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg==" + }, + "Microsoft.Extensions.Logging": { + "type": "Direct", + "requested": "[9.0.0, )", + "resolved": "9.0.0", + "contentHash": "crjWyORoug0kK7RSNJBTeSE6VX8IQgLf3nUpTB9m62bPXp/tzbnOsnbe8TXEG0AASNaKZddnpHKw7fET8E++Pg==", + "dependencies": { + "Microsoft.Extensions.Options": "9.0.0" + } + }, + "Microsoft.Extensions.Options": { + "type": "Transitive", + "resolved": "9.0.0", + "contentHash": "dzXN0+V1AyjOe2xcJ86Qbo233KHuLEY0njf/P2Kw8SfJU+d45HNS2ctJdnEnrWbM9Ye2eFgaC5Mj9otRMU6IsQ==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0", + "Microsoft.Extensions.Primitives": "9.0.0" + } + }, + "Microsoft.Extensions.Primitives": { + "type": "Transitive", + "resolved": "9.0.0", + "contentHash": "9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "9.0.0" + } + }, + "System.Runtime.CompilerServices.Unsafe": { + "type": "Transitive", + "resolved": "9.0.0", + "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" + } + }, + ".netcore2.0": { + "bootstrap": { + "type": "Direct", + "requested": "[5.0.0, )", + "resolved": "5.0.0", + "contentHash": "NKQFzFwrfWOMjTwr+X/2iJyCveuAGF+fNzkxyB0YW45+InVhcE9PUxoL1a8Vmc/Lq9E/CQd4DjO8kU32P4w/Gg==" + }, + "log4net": { + "type": "Direct", + "requested": "[1.2.15, )", + "resolved": "1.2.15", + "contentHash": "KPajjkU1rbF6uY2rnakbh36LB9z9FVcYlciyOi6C5SJ3AMNywxjCGxBTN/Hl5nQEinRLuWvHWPF8W7YHh9sONw==" + } + } + } +} \ No newline at end of file diff --git a/syft/pkg/dotnet.go b/syft/pkg/dotnet.go index 4477ac01bba..cf432e8ab7a 100644 --- a/syft/pkg/dotnet.go +++ b/syft/pkg/dotnet.go @@ -9,6 +9,14 @@ type DotnetDepsEntry struct { HashPath string `mapstructure:"hashPath" json:"hashPath"` } +// DotnetPackagesLockEntry is a struct that represents a single entry found in the "dependencies" section in a .NET packages.lock.json file. +type DotnetPackagesLockEntry struct { + Name string `mapstructure:"name" json:"name"` + Version string `mapstructure:"version" json:"version"` + ContentHash string `mapstructure:"contentHash" json:"contentHash"` + Type string `mapstructure:"type" json:"type"` +} + // DotnetPortableExecutableEntry is a struct that represents a single entry found within "VersionResources" section of a .NET Portable Executable binary file. type DotnetPortableExecutableEntry struct { AssemblyVersion string `json:"assemblyVersion"`