From 8478e0bef792a9890c832a8dea586c2621ebc531 Mon Sep 17 00:00:00 2001 From: Dan Luhring Date: Wed, 19 Jul 2023 15:34:07 -0400 Subject: [PATCH] Add support for parsing .NET assemblies (#1943) * Add support for parsing .NET assemblies Signed-off-by: Dan Luhring Former-commit-id: 69c33fe4d77357d843c11590f3b07825bc6249ac * Add dll and exe files Signed-off-by: Dan Luhring Former-commit-id: b9d204efa6d2ef385b5fbb7a59a3474ecabea641 * Add PE cataloger to directory catalogers Signed-off-by: Dan Luhring Former-commit-id: 9711c00d9da92e2887e0c1f92edd740ea5345849 * Don't set language to dotnet for PEs Signed-off-by: Dan Luhring Former-commit-id: 368313fddac9160d8a06a01ebe8c5ac7990232f5 * Fix spelling of cataloger in constructor Signed-off-by: Dan Luhring Former-commit-id: e42fd77b2f8b6d42e076a84f6cce386861260941 * Adjust which cases in PE parsing return errors Signed-off-by: Dan Luhring Former-commit-id: 95b25f8fc3a7d4e18fe30e489b09851f316795ff * remove build binary from branch Signed-off-by: Alex Goodman Former-commit-id: fa54c0d0aef0998d5520e9f44cae51f5f9cd38a2 * Fix failing CLI tests Signed-off-by: Dan Luhring --------- Signed-off-by: Dan Luhring Co-authored-by: Alex Goodman --- go.mod | 3 + go.sum | 7 + internal/constants.go | 2 +- schema/json/schema-9.0.1.json | 1917 +++++++++++++++++ syft/internal/packagemetadata/generated.go | 2 +- syft/pkg/cataloger/cataloger.go | 4 +- syft/pkg/cataloger/dotnet/cataloger.go | 9 +- syft/pkg/cataloger/dotnet/cataloger_test.go | 24 +- .../parse_dotnet_portable_executable.go | 87 + .../parse_dotnet_portable_executable_test.go | 38 + .../cataloger/dotnet/test-fixtures/.gitignore | 2 + .../dotnet/test-fixtures/System.Buffers.dll | Bin 0 -> 5120 bytes .../glob-paths/src/something.dll | 1 + .../glob-paths/src/something.exe | 1 + .../dotnet_portable_executable_metadata.go | 11 + syft/pkg/metadata.go | 125 +- test/cli/packages_cmd_test.go | 14 +- 17 files changed, 2167 insertions(+), 80 deletions(-) create mode 100644 schema/json/schema-9.0.1.json create mode 100644 syft/pkg/cataloger/dotnet/parse_dotnet_portable_executable.go create mode 100644 syft/pkg/cataloger/dotnet/parse_dotnet_portable_executable_test.go create mode 100644 syft/pkg/cataloger/dotnet/test-fixtures/.gitignore create mode 100644 syft/pkg/cataloger/dotnet/test-fixtures/System.Buffers.dll create mode 100644 syft/pkg/cataloger/dotnet/test-fixtures/glob-paths/src/something.dll create mode 100644 syft/pkg/cataloger/dotnet/test-fixtures/glob-paths/src/something.exe create mode 100644 syft/pkg/dotnet_portable_executable_metadata.go diff --git a/go.mod b/go.mod index 452223b95..813242280 100644 --- a/go.mod +++ b/go.mod @@ -69,6 +69,7 @@ require ( github.com/invopop/jsonschema v0.7.0 github.com/knqyf263/go-rpmdb v0.0.0-20230301153543-ba94b245509b github.com/opencontainers/go-digest v1.0.0 + github.com/saferwall/pe v1.4.4 github.com/sassoftware/go-rpmutils v0.2.0 github.com/vbatts/go-mtree v0.5.3 github.com/zyedidia/generic v1.2.2-0.20230320175451-4410d2372cb1 @@ -102,6 +103,7 @@ require ( github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect + github.com/edsrzf/mmap-go v1.1.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/felixge/fgprof v0.9.3 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect @@ -172,6 +174,7 @@ require ( github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect + go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 // indirect golang.org/x/sync v0.1.0 // indirect golang.org/x/sys v0.10.0 // indirect golang.org/x/text v0.11.0 // indirect diff --git a/go.sum b/go.sum index 142f3dad7..60b7f4769 100644 --- a/go.sum +++ b/go.sum @@ -197,6 +197,8 @@ github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj6 github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= +github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 h1:RIB4cRk+lBqKK3Oy0r2gRX4ui7tuhiZq2SuTtTCi0/0= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= @@ -583,6 +585,8 @@ github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZV github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/saferwall/pe v1.4.4 h1:Ml++7/2/Z1iKwV4zCsd1nIqTEAdUQKAetwbbcCarhOg= +github.com/saferwall/pe v1.4.4/go.mod h1:SNzv3cdgk8SBI0UwHfyTcdjawfdnN+nbydnEL7GZ25s= github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= github.com/sassoftware/go-rpmutils v0.2.0 h1:pKW0HDYMFWQ5b4JQPiI3WI12hGsVoW0V8+GMoZiI/JE= github.com/sassoftware/go-rpmutils v0.2.0/go.mod h1:TJJQYtLe/BeEmEjelI3b7xNZjzAukEkeWKmoakvaOoI= @@ -703,6 +707,8 @@ github.com/zyedidia/generic v1.2.2-0.20230320175451-4410d2372cb1/go.mod h1:ly2RB go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= +go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 h1:CCriYyAfq1Br1aIYettdHZTy8mBTIPo7We18TuO/bak= +go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -929,6 +935,7 @@ golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/internal/constants.go b/internal/constants.go index bf520ab90..e61d94348 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 = "9.0.0" + JSONSchemaVersion = "9.0.1" ) diff --git a/schema/json/schema-9.0.1.json b/schema/json/schema-9.0.1.json new file mode 100644 index 000000000..bfdcda5d8 --- /dev/null +++ b/schema/json/schema-9.0.1.json @@ -0,0 +1,1917 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "anchore.io/schema/syft/json/9.0.1/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" + }, + "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", + "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" + }, + "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" + ] + }, + "BinaryMetadata": { + "properties": { + "matches": { + "items": { + "$ref": "#/$defs/ClassifierMatch" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "matches" + ] + }, + "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" + ] + }, + "ClassifierMatch": { + "properties": { + "classifier": { + "type": "string" + }, + "location": { + "$ref": "#/$defs/Location" + } + }, + "type": "object", + "required": [ + "classifier", + "location" + ] + }, + "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" + ] + }, + "DotnetPortableExecutableMetadata": { + "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" + ] + }, + "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" + } + }, + "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" + }, + "size": { + "type": "integer" + } + }, + "type": "object", + "required": [ + "mode", + "type", + "userID", + "groupID", + "mimeType", + "size" + ] + }, + "GemMetadata": { + "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" + ] + }, + "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" + ] + }, + "GolangModMetadata": { + "properties": { + "h1Digest": { + "type": "string" + } + }, + "type": "object" + }, + "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" + ] + }, + "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" + ] + }, + "LinuxKernelMetadata": { + "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" + ] + }, + "LinuxKernelModuleMetadata": { + "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" + }, + "annotations": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object", + "required": [ + "path" + ] + }, + "MixLockMetadata": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "pkgHash": { + "type": "string" + }, + "pkgHashExt": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "version", + "pkgHash", + "pkgHashExt" + ] + }, + "NixStoreMetadata": { + "properties": { + "outputHash": { + "type": "string" + }, + "output": { + "type": "string" + }, + "files": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "outputHash", + "files" + ] + }, + "NpmPackageJSONMetadata": { + "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" + ] + }, + "NpmPackageLockJSONMetadata": { + "properties": { + "resolved": { + "type": "string" + }, + "integrity": { + "type": "string" + } + }, + "type": "object", + "required": [ + "resolved", + "integrity" + ] + }, + "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": { + "items": { + "type": "string" + }, + "type": "array" + }, + "purl": { + "type": "string" + }, + "metadataType": { + "type": "string" + }, + "metadata": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/AlpmMetadata" + }, + { + "$ref": "#/$defs/ApkMetadata" + }, + { + "$ref": "#/$defs/BinaryMetadata" + }, + { + "$ref": "#/$defs/CargoPackageMetadata" + }, + { + "$ref": "#/$defs/CocoapodsMetadata" + }, + { + "$ref": "#/$defs/ConanLockMetadata" + }, + { + "$ref": "#/$defs/ConanMetadata" + }, + { + "$ref": "#/$defs/DartPubMetadata" + }, + { + "$ref": "#/$defs/DotnetDepsMetadata" + }, + { + "$ref": "#/$defs/DotnetPortableExecutableMetadata" + }, + { + "$ref": "#/$defs/DpkgMetadata" + }, + { + "$ref": "#/$defs/GemMetadata" + }, + { + "$ref": "#/$defs/GolangBinMetadata" + }, + { + "$ref": "#/$defs/GolangModMetadata" + }, + { + "$ref": "#/$defs/HackageMetadata" + }, + { + "$ref": "#/$defs/JavaMetadata" + }, + { + "$ref": "#/$defs/KbPackageMetadata" + }, + { + "$ref": "#/$defs/LinuxKernelMetadata" + }, + { + "$ref": "#/$defs/LinuxKernelModuleMetadata" + }, + { + "$ref": "#/$defs/MixLockMetadata" + }, + { + "$ref": "#/$defs/NixStoreMetadata" + }, + { + "$ref": "#/$defs/NpmPackageJSONMetadata" + }, + { + "$ref": "#/$defs/NpmPackageLockJSONMetadata" + }, + { + "$ref": "#/$defs/PhpComposerJSONMetadata" + }, + { + "$ref": "#/$defs/PortageMetadata" + }, + { + "$ref": "#/$defs/PythonPackageMetadata" + }, + { + "$ref": "#/$defs/PythonPipfileLockMetadata" + }, + { + "$ref": "#/$defs/PythonRequirementsMetadata" + }, + { + "$ref": "#/$defs/RDescriptionFileMetadata" + }, + { + "$ref": "#/$defs/RebarLockMetadata" + }, + { + "$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" + }, + "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" + ] + }, + "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" + }, + "scope": { + "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" + }, + "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", + "author", + "authorEmail", + "platform", + "sitePackagesRootPath" + ] + }, + "PythonPipfileLockMetadata": { + "properties": { + "hashes": { + "items": { + "type": "string" + }, + "type": "array" + }, + "index": { + "type": "string" + } + }, + "type": "object", + "required": [ + "hashes", + "index" + ] + }, + "PythonRequirementsMetadata": { + "properties": { + "name": { + "type": "string" + }, + "extras": { + "items": { + "type": "string" + }, + "type": "array" + }, + "versionConstraint": { + "type": "string" + }, + "url": { + "type": "string" + }, + "markers": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object", + "required": [ + "name", + "extras", + "versionConstraint", + "url", + "markers" + ] + }, + "RDescriptionFileMetadata": { + "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" + }, + "RebarLockMetadata": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "pkgHash": { + "type": "string" + }, + "pkgHashExt": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "version", + "pkgHash", + "pkgHashExt" + ] + }, + "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" + }, + "vendor": { + "type": "string" + }, + "modularityLabel": { + "type": "string" + }, + "files": { + "items": { + "$ref": "#/$defs/RpmdbFileRecord" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "name", + "version", + "epoch", + "architecture", + "release", + "sourceRpm", + "size", + "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" + }, + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "type": { + "type": "string" + }, + "metadata": true + }, + "type": "object", + "required": [ + "id", + "name", + "version", + "type", + "metadata" + ] + }, + "licenses": { + "items": { + "$ref": "#/$defs/License" + }, + "type": "array" + } + } +} diff --git a/syft/internal/packagemetadata/generated.go b/syft/internal/packagemetadata/generated.go index 42bca884f..d614bce0a 100644 --- a/syft/internal/packagemetadata/generated.go +++ b/syft/internal/packagemetadata/generated.go @@ -6,5 +6,5 @@ import "github.com/anchore/syft/syft/pkg" // AllTypes returns a list of all pkg metadata types that syft supports (that are represented in the pkg.Package.Metadata field). func AllTypes() []any { - return []any{pkg.AlpmMetadata{}, pkg.ApkMetadata{}, pkg.BinaryMetadata{}, pkg.CargoPackageMetadata{}, pkg.CocoapodsMetadata{}, pkg.ConanLockMetadata{}, pkg.ConanMetadata{}, pkg.DartPubMetadata{}, pkg.DotnetDepsMetadata{}, pkg.DpkgMetadata{}, pkg.GemMetadata{}, pkg.GolangBinMetadata{}, pkg.GolangModMetadata{}, pkg.HackageMetadata{}, pkg.JavaMetadata{}, pkg.KbPackageMetadata{}, pkg.LinuxKernelMetadata{}, pkg.LinuxKernelModuleMetadata{}, pkg.MixLockMetadata{}, pkg.NixStoreMetadata{}, pkg.NpmPackageJSONMetadata{}, pkg.NpmPackageLockJSONMetadata{}, pkg.PhpComposerJSONMetadata{}, pkg.PortageMetadata{}, pkg.PythonPackageMetadata{}, pkg.PythonPipfileLockMetadata{}, pkg.PythonRequirementsMetadata{}, pkg.RDescriptionFileMetadata{}, pkg.RebarLockMetadata{}, pkg.RpmMetadata{}} + return []any{pkg.AlpmMetadata{}, pkg.ApkMetadata{}, pkg.BinaryMetadata{}, pkg.CargoPackageMetadata{}, pkg.CocoapodsMetadata{}, pkg.ConanLockMetadata{}, pkg.ConanMetadata{}, pkg.DartPubMetadata{}, pkg.DotnetDepsMetadata{}, pkg.DotnetPortableExecutableMetadata{}, pkg.DpkgMetadata{}, pkg.GemMetadata{}, pkg.GolangBinMetadata{}, pkg.GolangModMetadata{}, pkg.HackageMetadata{}, pkg.JavaMetadata{}, pkg.KbPackageMetadata{}, pkg.LinuxKernelMetadata{}, pkg.LinuxKernelModuleMetadata{}, pkg.MixLockMetadata{}, pkg.NixStoreMetadata{}, pkg.NpmPackageJSONMetadata{}, pkg.NpmPackageLockJSONMetadata{}, pkg.PhpComposerJSONMetadata{}, pkg.PortageMetadata{}, pkg.PythonPackageMetadata{}, pkg.PythonPipfileLockMetadata{}, pkg.PythonRequirementsMetadata{}, pkg.RDescriptionFileMetadata{}, pkg.RebarLockMetadata{}, pkg.RpmMetadata{}} } diff --git a/syft/pkg/cataloger/cataloger.go b/syft/pkg/cataloger/cataloger.go index 78a995843..acb6e9e59 100644 --- a/syft/pkg/cataloger/cataloger.go +++ b/syft/pkg/cataloger/cataloger.go @@ -45,7 +45,7 @@ func ImageCatalogers(cfg Config) []pkg.Cataloger { apkdb.NewApkdbCataloger(), binary.NewCataloger(), deb.NewDpkgdbCataloger(), - dotnet.NewDotnetDepsCataloger(), + dotnet.NewDotnetPortableExecutableCataloger(), golang.NewGoModuleBinaryCataloger(cfg.Go()), java.NewJavaCataloger(cfg.Java()), java.NewNativeImageCataloger(), @@ -71,6 +71,7 @@ func DirectoryCatalogers(cfg Config) []pkg.Cataloger { dart.NewPubspecLockCataloger(), deb.NewDpkgdbCataloger(), dotnet.NewDotnetDepsCataloger(), + dotnet.NewDotnetPortableExecutableCataloger(), elixir.NewMixLockCataloger(), erlang.NewRebarLockCataloger(), golang.NewGoModFileCataloger(cfg.Go()), @@ -105,6 +106,7 @@ func AllCatalogers(cfg Config) []pkg.Cataloger { dart.NewPubspecLockCataloger(), deb.NewDpkgdbCataloger(), dotnet.NewDotnetDepsCataloger(), + dotnet.NewDotnetPortableExecutableCataloger(), elixir.NewMixLockCataloger(), erlang.NewRebarLockCataloger(), golang.NewGoModFileCataloger(cfg.Go()), diff --git a/syft/pkg/cataloger/dotnet/cataloger.go b/syft/pkg/cataloger/dotnet/cataloger.go index 159edcb27..938ccfbac 100644 --- a/syft/pkg/cataloger/dotnet/cataloger.go +++ b/syft/pkg/cataloger/dotnet/cataloger.go @@ -4,10 +4,13 @@ import ( "github.com/anchore/syft/syft/pkg/cataloger/generic" ) -const catalogerName = "dotnet-deps-cataloger" - // NewDotnetDepsCataloger returns a new Dotnet cataloger object base on deps json files. func NewDotnetDepsCataloger() *generic.Cataloger { - return generic.NewCataloger(catalogerName). + return generic.NewCataloger("dotnet-deps-cataloger"). WithParserByGlobs(parseDotnetDeps, "**/*.deps.json") } + +func NewDotnetPortableExecutableCataloger() *generic.Cataloger { + return generic.NewCataloger("dotnet-portable-executable-cataloger"). + WithParserByGlobs(parseDotnetPortableExecutable, "**/*.dll", "**/*.exe") +} diff --git a/syft/pkg/cataloger/dotnet/cataloger_test.go b/syft/pkg/cataloger/dotnet/cataloger_test.go index 8b1314491..ff09be567 100644 --- a/syft/pkg/cataloger/dotnet/cataloger_test.go +++ b/syft/pkg/cataloger/dotnet/cataloger_test.go @@ -3,22 +3,34 @@ package dotnet import ( "testing" + "github.com/anchore/syft/syft/pkg/cataloger/generic" "github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest" ) func TestCataloger_Globs(t *testing.T) { tests := []struct { - name string - fixture string - expected []string + name string + fixture string + cataloger *generic.Cataloger + expected []string }{ { - name: "obtain deps.json files", - fixture: "test-fixtures/glob-paths", + name: "obtain deps.json files", + fixture: "test-fixtures/glob-paths", + cataloger: NewDotnetDepsCataloger(), expected: []string{ "src/something.deps.json", }, }, + { + name: "obtain portable executable files", + fixture: "test-fixtures/glob-paths", + cataloger: NewDotnetPortableExecutableCataloger(), + expected: []string{ + "src/something.dll", + "src/something.exe", + }, + }, } for _, test := range tests { @@ -26,7 +38,7 @@ func TestCataloger_Globs(t *testing.T) { pkgtest.NewCatalogTester(). FromDirectory(t, test.fixture). ExpectsResolverContentQueries(test.expected). - TestCataloger(t, NewDotnetDepsCataloger()) + TestCataloger(t, test.cataloger) }) } } diff --git a/syft/pkg/cataloger/dotnet/parse_dotnet_portable_executable.go b/syft/pkg/cataloger/dotnet/parse_dotnet_portable_executable.go new file mode 100644 index 000000000..b57b2f06e --- /dev/null +++ b/syft/pkg/cataloger/dotnet/parse_dotnet_portable_executable.go @@ -0,0 +1,87 @@ +package dotnet + +import ( + "fmt" + "io" + + "github.com/saferwall/pe" + + "github.com/anchore/packageurl-go" + "github.com/anchore/syft/internal/log" + "github.com/anchore/syft/syft/artifact" + "github.com/anchore/syft/syft/file" + "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/pkg/cataloger/generic" +) + +var _ generic.Parser = parseDotnetPortableExecutable + +func parseDotnetPortableExecutable(_ file.Resolver, _ *generic.Environment, f file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) { + by, err := io.ReadAll(f) + if err != nil { + return nil, nil, fmt.Errorf("unable to read file: %w", err) + } + + peFile, err := pe.NewBytes(by, &pe.Options{}) + if err != nil { + return nil, nil, fmt.Errorf("unable to create PE file instance: %w", err) + } + + err = peFile.Parse() + if err != nil { + return nil, nil, fmt.Errorf("unable to parse PE file: %w", err) + } + + versionResources, err := peFile.ParseVersionResources() + if err != nil { + // this is not a fatal error, just log and continue + // TODO: consider this case for "known unknowns" (same goes for cases below) + log.Tracef("unable to parse version resources in PE file: %s", f.RealPath) + return nil, nil, nil + } + + name := versionResources["FileDescription"] + if name == "" { + log.Tracef("unable to find FileDescription in PE file: %s", f.RealPath) + return nil, nil, nil + } + + version := versionResources["FileVersion"] + if version == "" { + log.Tracef("unable to find FileVersion in PE file: %s", f.RealPath) + return nil, nil, nil + } + + purl := packageurl.NewPackageURL( + packageurl.TypeNuget, // See explanation in syft/pkg/cataloger/dotnet/package.go as to why this was chosen. + "", + name, + version, + nil, + "", + ).ToString() + + metadata := pkg.DotnetPortableExecutableMetadata{ + AssemblyVersion: versionResources["Assembly Version"], + LegalCopyright: versionResources["LegalCopyright"], + Comments: versionResources["Comments"], + InternalName: versionResources["InternalName"], + CompanyName: versionResources["CompanyName"], + ProductName: versionResources["ProductName"], + ProductVersion: versionResources["ProductVersion"], + } + + p := pkg.Package{ + Name: name, + Version: version, + Locations: file.NewLocationSet(f.Location), + Type: pkg.DotnetPkg, + PURL: purl, + MetadataType: pkg.DotnetPortableExecutableMetadataType, + Metadata: metadata, + } + + p.SetID() + + return []pkg.Package{p}, nil, nil +} diff --git a/syft/pkg/cataloger/dotnet/parse_dotnet_portable_executable_test.go b/syft/pkg/cataloger/dotnet/parse_dotnet_portable_executable_test.go new file mode 100644 index 000000000..0e10582ec --- /dev/null +++ b/syft/pkg/cataloger/dotnet/parse_dotnet_portable_executable_test.go @@ -0,0 +1,38 @@ +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 TestParseDotnetPortableExecutable(t *testing.T) { + fixture := "test-fixtures/System.Buffers.dll" + fixtureLocationSet := file.NewLocationSet(file.NewLocation(fixture)) + + expected := []pkg.Package{ + { + Name: "System.Buffers", + Version: "7.0.923.36201", + Locations: fixtureLocationSet, + Type: pkg.DotnetPkg, + PURL: "pkg:nuget/System.Buffers@7.0.923.36201", + MetadataType: pkg.DotnetPortableExecutableMetadataType, + Metadata: pkg.DotnetPortableExecutableMetadata{ + AssemblyVersion: "7.0.0.0", + LegalCopyright: "© Microsoft Corporation. All rights reserved.", + Comments: "System.Buffers", + InternalName: "System.Buffers.dll", + CompanyName: "Microsoft Corporation", + ProductName: "Microsoft® .NET", + ProductVersion: "7.0.9+8e9a17b2216f51a5788f8b1c467a4cf3b769e7d7", + }, + }, + } + + var expectedRelationships []artifact.Relationship + pkgtest.TestFileParser(t, fixture, parseDotnetPortableExecutable, expected, expectedRelationships) +} diff --git a/syft/pkg/cataloger/dotnet/test-fixtures/.gitignore b/syft/pkg/cataloger/dotnet/test-fixtures/.gitignore new file mode 100644 index 000000000..027ad4668 --- /dev/null +++ b/syft/pkg/cataloger/dotnet/test-fixtures/.gitignore @@ -0,0 +1,2 @@ +!*.dll +!*.exe \ No newline at end of file diff --git a/syft/pkg/cataloger/dotnet/test-fixtures/System.Buffers.dll b/syft/pkg/cataloger/dotnet/test-fixtures/System.Buffers.dll new file mode 100644 index 0000000000000000000000000000000000000000..a4cfb73e6e3e90e1732861e982a4890962cac0f6 GIT binary patch literal 5120 zcmeHLeQZEyUMN33 z|FE?7^!&ad&63lmkucSy992^(!iVL55Um@;iz#X`q*PY2Ojsfe~c z;C?zk+XY%6PnGJ4Dj+G#N!?4(%BXFqM3sVf<#2NW$1lnlDCB40t%wG9a8v#_(K=l& zLOF6L(K^nw5%rBb;R2@&5`6~jg~ib4Wgn-N$Ds@BGW1s!j8kkjYNKCM4g#H6D{vPU znP^ZkEi($Cz}5z)6qN%iC~ZKmm`pcdC{%+`a$hr03rZVNdqG#Qf5-ZH;n-YMLOn9# zGlhu5DlCIo|5%~mCVYE%b-P58&~hvzKBZo1tZ(!-b5RNDpa-C?y`N|vFn$@eHf)<( zDq(SpQRIN9p|(FvUkAfeS9?!?X9(@X=s(Eq+jS#?J}>A>Q)-C5#XIjyjWi1auzVbE zr=#*Pa6Vs&&Pkl-!IY$Vu2OnJ&{isUO{W&PETzqKOe&=Bc zOwd<_e7m4~1f4JBVeov8X`Eng2{A2lNmK<|N}mI*pe3M{22^^;9DV!0-#?L@nQXsO)7g4vTAGoXtn5t14Ku0QP^$V(twPL- znp&D$O?DAtaW$jcL0wa=3GE6anbvgSxR>ebsNf3p`PKB8h)vX<7?@YAFw$95OAHmL zR;&$kx0onZAnj#wX0lY2x)4KptfX=);6Shg0m@*)R=l8Y2G!^|AfqReuVkLj>&&~?x_ zbBbL?wD_Ht!0YA<-3OOl{N|?T6Mv*)S(3_%WRgn2R8{e=yF_+LZZ~ILWd~XZwpP7f zv21J)EyT4mM)W=dN^>`j317WW~FsC+l{kQ#z)AoDCRfUT#06K!MJ69FF`j`qNz@9 z_<=0$GcznF?J@b*>r6$AQAb)Wk^B05m5A?%IhdhKi<*XI#BCW+(}pR|1W}_z%JFC9 z8)_9fsOz#g2bOFy3wwmc6x{O?O#^tPxuH>M^f%Odb8dvFu8B3P-aw?G!RwDN^{Pt) zO-=Eph&Sr<2UK4)-WUn^n^_OUIpeM^f}87?JK5*|twa)wpFQcRCr&HX-$2eou?lrV8_|3GhlEq! zEAoL`k5|P2Xb1Iz>%>dD8~skumAO|p9V>q8YVKt=g|tU@!vlXwlvAtY2luaYqd5XJ zAyf%oRWjj6!<&-9XNuxv2&0AK1=$C!3aJIXN;d2a^m64u@dnH!0h0|Y4f4bdJo$u8 zJ=UH3_$b0-Kz_U`CA^&sO5(#X+QuvdZ&|c9BuTuy+9?A>ar8`~#qS)vi}K^r0$Uc5 zP=ybUs|!e?ur^?CV5E)B$Y(JrEok8?RtgOH)rT;PCB|y7EnMq=!_-1l{nI8~8f%G2uO) z7@X6 zXahc8WGPNd(W;;USTv#E1g#fne9#7<@qv#cqY?D{@W9ZdqYADEqwTXjvyjg jpu8ClzDM}k__Tb&A|U7fXHY4ApMS!ze+u`1j=+Ba@y|BX literal 0 HcmV?d00001 diff --git a/syft/pkg/cataloger/dotnet/test-fixtures/glob-paths/src/something.dll b/syft/pkg/cataloger/dotnet/test-fixtures/glob-paths/src/something.dll new file mode 100644 index 000000000..ae2d5a27a --- /dev/null +++ b/syft/pkg/cataloger/dotnet/test-fixtures/glob-paths/src/something.dll @@ -0,0 +1 @@ +bogus .dll (portable executable) \ No newline at end of file diff --git a/syft/pkg/cataloger/dotnet/test-fixtures/glob-paths/src/something.exe b/syft/pkg/cataloger/dotnet/test-fixtures/glob-paths/src/something.exe new file mode 100644 index 000000000..39fc969a3 --- /dev/null +++ b/syft/pkg/cataloger/dotnet/test-fixtures/glob-paths/src/something.exe @@ -0,0 +1 @@ +bogus .exe portable executable) \ No newline at end of file diff --git a/syft/pkg/dotnet_portable_executable_metadata.go b/syft/pkg/dotnet_portable_executable_metadata.go new file mode 100644 index 000000000..7b42d133a --- /dev/null +++ b/syft/pkg/dotnet_portable_executable_metadata.go @@ -0,0 +1,11 @@ +package pkg + +type DotnetPortableExecutableMetadata struct { + AssemblyVersion string `json:"assemblyVersion"` + LegalCopyright string `json:"legalCopyright"` + Comments string `json:"comments,omitempty"` + InternalName string `json:"internalName,omitempty"` + CompanyName string `json:"companyName"` + ProductName string `json:"productName"` + ProductVersion string `json:"productVersion"` +} diff --git a/syft/pkg/metadata.go b/syft/pkg/metadata.go index 5d43e9911..689300b38 100644 --- a/syft/pkg/metadata.go +++ b/syft/pkg/metadata.go @@ -10,37 +10,38 @@ type MetadataType string const ( // this is the full set of data shapes that can be represented within the pkg.Package.Metadata field - UnknownMetadataType MetadataType = "UnknownMetadata" - AlpmMetadataType MetadataType = "AlpmMetadata" - ApkMetadataType MetadataType = "ApkMetadata" - BinaryMetadataType MetadataType = "BinaryMetadata" - CocoapodsMetadataType MetadataType = "CocoapodsMetadataType" - ConanLockMetadataType MetadataType = "ConanLockMetadataType" - ConanMetadataType MetadataType = "ConanMetadataType" - DartPubMetadataType MetadataType = "DartPubMetadata" - DotnetDepsMetadataType MetadataType = "DotnetDepsMetadata" - DpkgMetadataType MetadataType = "DpkgMetadata" - GemMetadataType MetadataType = "GemMetadata" - GolangBinMetadataType MetadataType = "GolangBinMetadata" - GolangModMetadataType MetadataType = "GolangModMetadata" - HackageMetadataType MetadataType = "HackageMetadataType" - JavaMetadataType MetadataType = "JavaMetadata" - KbPackageMetadataType MetadataType = "KbPackageMetadata" - LinuxKernelMetadataType MetadataType = "LinuxKernelMetadata" - LinuxKernelModuleMetadataType MetadataType = "LinuxKernelModuleMetadata" - MixLockMetadataType MetadataType = "MixLockMetadataType" - NixStoreMetadataType MetadataType = "NixStoreMetadata" - NpmPackageJSONMetadataType MetadataType = "NpmPackageJsonMetadata" - NpmPackageLockJSONMetadataType MetadataType = "NpmPackageLockJsonMetadata" - PhpComposerJSONMetadataType MetadataType = "PhpComposerJsonMetadata" - PortageMetadataType MetadataType = "PortageMetadata" - PythonPackageMetadataType MetadataType = "PythonPackageMetadata" - PythonPipfileLockMetadataType MetadataType = "PythonPipfileLockMetadata" - PythonRequirementsMetadataType MetadataType = "PythonRequirementsMetadata" - RebarLockMetadataType MetadataType = "RebarLockMetadataType" - RDescriptionFileMetadataType MetadataType = "RDescriptionFileMetadataType" - RpmMetadataType MetadataType = "RpmMetadata" - RustCargoPackageMetadataType MetadataType = "RustCargoPackageMetadata" + UnknownMetadataType MetadataType = "UnknownMetadata" + AlpmMetadataType MetadataType = "AlpmMetadata" + ApkMetadataType MetadataType = "ApkMetadata" + BinaryMetadataType MetadataType = "BinaryMetadata" + CocoapodsMetadataType MetadataType = "CocoapodsMetadataType" + ConanLockMetadataType MetadataType = "ConanLockMetadataType" + ConanMetadataType MetadataType = "ConanMetadataType" + DartPubMetadataType MetadataType = "DartPubMetadata" + DotnetDepsMetadataType MetadataType = "DotnetDepsMetadata" + DotnetPortableExecutableMetadataType MetadataType = "DotnetPortableExecutableMetadata" + DpkgMetadataType MetadataType = "DpkgMetadata" + GemMetadataType MetadataType = "GemMetadata" + GolangBinMetadataType MetadataType = "GolangBinMetadata" + GolangModMetadataType MetadataType = "GolangModMetadata" + HackageMetadataType MetadataType = "HackageMetadataType" + JavaMetadataType MetadataType = "JavaMetadata" + KbPackageMetadataType MetadataType = "KbPackageMetadata" + LinuxKernelMetadataType MetadataType = "LinuxKernelMetadata" + LinuxKernelModuleMetadataType MetadataType = "LinuxKernelModuleMetadata" + MixLockMetadataType MetadataType = "MixLockMetadataType" + NixStoreMetadataType MetadataType = "NixStoreMetadata" + NpmPackageJSONMetadataType MetadataType = "NpmPackageJsonMetadata" + NpmPackageLockJSONMetadataType MetadataType = "NpmPackageLockJsonMetadata" + PhpComposerJSONMetadataType MetadataType = "PhpComposerJsonMetadata" + PortageMetadataType MetadataType = "PortageMetadata" + PythonPackageMetadataType MetadataType = "PythonPackageMetadata" + PythonPipfileLockMetadataType MetadataType = "PythonPipfileLockMetadata" + PythonRequirementsMetadataType MetadataType = "PythonRequirementsMetadata" + RebarLockMetadataType MetadataType = "RebarLockMetadataType" + RDescriptionFileMetadataType MetadataType = "RDescriptionFileMetadataType" + RpmMetadataType MetadataType = "RpmMetadata" + RustCargoPackageMetadataType MetadataType = "RustCargoPackageMetadata" ) var AllMetadataTypes = []MetadataType{ @@ -52,6 +53,7 @@ var AllMetadataTypes = []MetadataType{ ConanMetadataType, DartPubMetadataType, DotnetDepsMetadataType, + DotnetPortableExecutableMetadataType, DpkgMetadataType, GemMetadataType, GolangBinMetadataType, @@ -77,36 +79,37 @@ var AllMetadataTypes = []MetadataType{ } var MetadataTypeByName = map[MetadataType]reflect.Type{ - AlpmMetadataType: reflect.TypeOf(AlpmMetadata{}), - ApkMetadataType: reflect.TypeOf(ApkMetadata{}), - BinaryMetadataType: reflect.TypeOf(BinaryMetadata{}), - CocoapodsMetadataType: reflect.TypeOf(CocoapodsMetadata{}), - ConanLockMetadataType: reflect.TypeOf(ConanLockMetadata{}), - ConanMetadataType: reflect.TypeOf(ConanMetadata{}), - DartPubMetadataType: reflect.TypeOf(DartPubMetadata{}), - DotnetDepsMetadataType: reflect.TypeOf(DotnetDepsMetadata{}), - DpkgMetadataType: reflect.TypeOf(DpkgMetadata{}), - GemMetadataType: reflect.TypeOf(GemMetadata{}), - GolangBinMetadataType: reflect.TypeOf(GolangBinMetadata{}), - GolangModMetadataType: reflect.TypeOf(GolangModMetadata{}), - HackageMetadataType: reflect.TypeOf(HackageMetadata{}), - JavaMetadataType: reflect.TypeOf(JavaMetadata{}), - KbPackageMetadataType: reflect.TypeOf(KbPackageMetadata{}), - LinuxKernelMetadataType: reflect.TypeOf(LinuxKernelMetadata{}), - LinuxKernelModuleMetadataType: reflect.TypeOf(LinuxKernelModuleMetadata{}), - MixLockMetadataType: reflect.TypeOf(MixLockMetadata{}), - NixStoreMetadataType: reflect.TypeOf(NixStoreMetadata{}), - NpmPackageJSONMetadataType: reflect.TypeOf(NpmPackageJSONMetadata{}), - NpmPackageLockJSONMetadataType: reflect.TypeOf(NpmPackageLockJSONMetadata{}), - PhpComposerJSONMetadataType: reflect.TypeOf(PhpComposerJSONMetadata{}), - PortageMetadataType: reflect.TypeOf(PortageMetadata{}), - PythonPackageMetadataType: reflect.TypeOf(PythonPackageMetadata{}), - PythonPipfileLockMetadataType: reflect.TypeOf(PythonPipfileLockMetadata{}), - PythonRequirementsMetadataType: reflect.TypeOf(PythonRequirementsMetadata{}), - RDescriptionFileMetadataType: reflect.TypeOf(RDescriptionFileMetadata{}), - RebarLockMetadataType: reflect.TypeOf(RebarLockMetadata{}), - RpmMetadataType: reflect.TypeOf(RpmMetadata{}), - RustCargoPackageMetadataType: reflect.TypeOf(CargoPackageMetadata{}), + AlpmMetadataType: reflect.TypeOf(AlpmMetadata{}), + ApkMetadataType: reflect.TypeOf(ApkMetadata{}), + BinaryMetadataType: reflect.TypeOf(BinaryMetadata{}), + CocoapodsMetadataType: reflect.TypeOf(CocoapodsMetadata{}), + ConanLockMetadataType: reflect.TypeOf(ConanLockMetadata{}), + ConanMetadataType: reflect.TypeOf(ConanMetadata{}), + DartPubMetadataType: reflect.TypeOf(DartPubMetadata{}), + DotnetDepsMetadataType: reflect.TypeOf(DotnetDepsMetadata{}), + DotnetPortableExecutableMetadataType: reflect.TypeOf(DotnetPortableExecutableMetadata{}), + DpkgMetadataType: reflect.TypeOf(DpkgMetadata{}), + GemMetadataType: reflect.TypeOf(GemMetadata{}), + GolangBinMetadataType: reflect.TypeOf(GolangBinMetadata{}), + GolangModMetadataType: reflect.TypeOf(GolangModMetadata{}), + HackageMetadataType: reflect.TypeOf(HackageMetadata{}), + JavaMetadataType: reflect.TypeOf(JavaMetadata{}), + KbPackageMetadataType: reflect.TypeOf(KbPackageMetadata{}), + LinuxKernelMetadataType: reflect.TypeOf(LinuxKernelMetadata{}), + LinuxKernelModuleMetadataType: reflect.TypeOf(LinuxKernelModuleMetadata{}), + MixLockMetadataType: reflect.TypeOf(MixLockMetadata{}), + NixStoreMetadataType: reflect.TypeOf(NixStoreMetadata{}), + NpmPackageJSONMetadataType: reflect.TypeOf(NpmPackageJSONMetadata{}), + NpmPackageLockJSONMetadataType: reflect.TypeOf(NpmPackageLockJSONMetadata{}), + PhpComposerJSONMetadataType: reflect.TypeOf(PhpComposerJSONMetadata{}), + PortageMetadataType: reflect.TypeOf(PortageMetadata{}), + PythonPackageMetadataType: reflect.TypeOf(PythonPackageMetadata{}), + PythonPipfileLockMetadataType: reflect.TypeOf(PythonPipfileLockMetadata{}), + PythonRequirementsMetadataType: reflect.TypeOf(PythonRequirementsMetadata{}), + RDescriptionFileMetadataType: reflect.TypeOf(RDescriptionFileMetadata{}), + RebarLockMetadataType: reflect.TypeOf(RebarLockMetadata{}), + RpmMetadataType: reflect.TypeOf(RpmMetadata{}), + RustCargoPackageMetadataType: reflect.TypeOf(CargoPackageMetadata{}), } func CleanMetadataType(typ MetadataType) MetadataType { diff --git a/test/cli/packages_cmd_test.go b/test/cli/packages_cmd_test.go index 0cd68ffed..4bd0643d3 100644 --- a/test/cli/packages_cmd_test.go +++ b/test/cli/packages_cmd_test.go @@ -10,7 +10,7 @@ func TestPackagesCmdFlags(t *testing.T) { hiddenPackagesImage := "docker-archive:" + getFixtureImage(t, "image-hidden-packages") coverageImage := "docker-archive:" + getFixtureImage(t, "image-pkg-coverage") nodeBinaryImage := "docker-archive:" + getFixtureImage(t, "image-node-binary") - //badBinariesImage := "docker-archive:" + getFixtureImage(t, "image-bad-binaries") + // badBinariesImage := "docker-archive:" + getFixtureImage(t, "image-bad-binaries") tmp := t.TempDir() + "/" tests := []struct { @@ -51,7 +51,7 @@ func TestPackagesCmdFlags(t *testing.T) { // fail: https://github.com/anchore/syft/runs/4611343586?check_suite_focus=true // For the meantime this test will be commented out, but should be added back in as soon as possible. // - //{ + // { // name: "regression-survive-bad-binaries", // // this image has all sorts of rich binaries from the clang-13 test suite that should do pretty bad things // // to the go cataloger binary path. We should NEVER let a panic stop the cataloging process for these @@ -64,7 +64,7 @@ func TestPackagesCmdFlags(t *testing.T) { // assertInOutput("could not parse possible go binary"), // assertSuccessfulReturnCode, // }, - //}, + // }, { name: "output-env-binding", env: map[string]string{ @@ -96,7 +96,7 @@ func TestPackagesCmdFlags(t *testing.T) { name: "squashed-scope-flag", args: []string{"packages", "-o", "json", "-s", "squashed", coverageImage}, assertions: []traitAssertion{ - assertPackageCount(36), + assertPackageCount(24), assertSuccessfulReturnCode, }, }, @@ -213,7 +213,7 @@ func TestPackagesCmdFlags(t *testing.T) { // the application config in the log matches that of what we expect to have been configured. assertInOutput("parallelism: 2"), assertInOutput("parallelism=2"), - assertPackageCount(36), + assertPackageCount(24), assertSuccessfulReturnCode, }, }, @@ -224,7 +224,7 @@ func TestPackagesCmdFlags(t *testing.T) { // the application config in the log matches that of what we expect to have been configured. assertInOutput("parallelism: 1"), assertInOutput("parallelism=1"), - assertPackageCount(36), + assertPackageCount(24), assertSuccessfulReturnCode, }, }, @@ -238,7 +238,7 @@ func TestPackagesCmdFlags(t *testing.T) { assertions: []traitAssertion{ assertNotInOutput("secret_password"), assertNotInOutput("secret_key_path"), - assertPackageCount(36), + assertPackageCount(24), assertSuccessfulReturnCode, }, },