From 4839075c284f5ede6d8ed897a14e1d27388a3c3a Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Wed, 7 Sep 2022 00:59:13 +0600 Subject: [PATCH] feat: add support for conan.lock file (#2779) Co-authored-by: knqyf263 --- .github/workflows/semantic-pr.yaml | 2 + .../vulnerability/detection/data-source.md | 33 ++--- docs/docs/vulnerability/detection/language.md | 2 + go.mod | 2 +- go.sum | 4 +- integration/fs_test.go | 9 ++ integration/integration_test.go | 1 - integration/testdata/conan.json.golden | 76 +++++++++++ integration/testdata/fixtures/db/conan.yaml | 10 ++ .../testdata/fixtures/db/vulnerability.yaml | 25 +++- .../testdata/fixtures/fs/conan/conan.lock | 77 ++++++++++++ pkg/detector/library/detect.go | 2 +- pkg/detector/library/driver.go | 5 + pkg/fanal/analyzer/all/import.go | 1 + pkg/fanal/analyzer/const.go | 7 +- pkg/fanal/analyzer/language/c/conan/conan.go | 48 +++++++ .../analyzer/language/c/conan/conan_test.go | 118 ++++++++++++++++++ .../language/c/conan/testdata/empty.lock | 14 +++ .../language/c/conan/testdata/happy.lock | 34 +++++ pkg/fanal/types/const.go | 3 + 20 files changed, 449 insertions(+), 24 deletions(-) create mode 100644 integration/testdata/conan.json.golden create mode 100644 integration/testdata/fixtures/db/conan.yaml create mode 100644 integration/testdata/fixtures/fs/conan/conan.lock create mode 100644 pkg/fanal/analyzer/language/c/conan/conan.go create mode 100644 pkg/fanal/analyzer/language/c/conan/conan_test.go create mode 100644 pkg/fanal/analyzer/language/c/conan/testdata/empty.lock create mode 100644 pkg/fanal/analyzer/language/c/conan/testdata/happy.lock diff --git a/.github/workflows/semantic-pr.yaml b/.github/workflows/semantic-pr.yaml index 6c314884580..093f7f869c2 100644 --- a/.github/workflows/semantic-pr.yaml +++ b/.github/workflows/semantic-pr.yaml @@ -64,6 +64,8 @@ jobs: dotnet java go + c + c++ os lang diff --git a/docs/docs/vulnerability/detection/data-source.md b/docs/docs/vulnerability/detection/data-source.md index e23528eba17..405e535df52 100644 --- a/docs/docs/vulnerability/detection/data-source.md +++ b/docs/docs/vulnerability/detection/data-source.md @@ -19,22 +19,23 @@ # Programming Language -| Language | Source | Commercial Use | Delay[^1]| -| ---------------------------- | ----------------------------------------------------|:---------------:|:--------:| -| PHP | [PHP Security Advisories Database][php] | ✅ | - | -| | [GitHub Advisory Database (Composer)][php-ghsa] | ✅ | - | -| Python | [GitHub Advisory Database (pip)][python-ghsa] | ✅ | - | -| | [Open Source Vulnerabilities (PyPI)][python-osv] | ✅ | - | -| Ruby | [Ruby Advisory Database][ruby] | ✅ | - | -| | [GitHub Advisory Database (RubyGems)][ruby-ghsa] | ✅ | - | -| Node.js | [Ecosystem Security Working Group][nodejs] | ✅ | - | -| | [GitHub Advisory Database (npm)][nodejs-ghsa] | ✅ | - | -| Java | [GitLab Advisories Community][gitlab] | ✅ | 1 month | -| | [GitHub Advisory Database (Maven)][java-ghsa] | ✅ | - | -| Go | [GitLab Advisories Community][gitlab] | ✅ | 1 month | -| | [The Go Vulnerability Database][go] | ✅ | - | -| Rust | [Open Source Vulnerabilities (crates.io)][rust-osv] | ✅ | - | -| .NET | [GitHub Advisory Database (NuGet)][dotnet-ghsa] | ✅ | - | +| Language | Source | Commercial Use | Delay[^1]| +|----------|-----------------------------------------------------|:---------------:|:--------:| +| PHP | [PHP Security Advisories Database][php] | ✅ | - | +| | [GitHub Advisory Database (Composer)][php-ghsa] | ✅ | - | +| Python | [GitHub Advisory Database (pip)][python-ghsa] | ✅ | - | +| | [Open Source Vulnerabilities (PyPI)][python-osv] | ✅ | - | +| Ruby | [Ruby Advisory Database][ruby] | ✅ | - | +| | [GitHub Advisory Database (RubyGems)][ruby-ghsa] | ✅ | - | +| Node.js | [Ecosystem Security Working Group][nodejs] | ✅ | - | +| | [GitHub Advisory Database (npm)][nodejs-ghsa] | ✅ | - | +| Java | [GitLab Advisories Community][gitlab] | ✅ | 1 month | +| | [GitHub Advisory Database (Maven)][java-ghsa] | ✅ | - | +| Go | [GitLab Advisories Community][gitlab] | ✅ | 1 month | +| | [The Go Vulnerability Database][go] | ✅ | - | +| Rust | [Open Source Vulnerabilities (crates.io)][rust-osv] | ✅ | - | +| .NET | [GitHub Advisory Database (NuGet)][dotnet-ghsa] | ✅ | - | +| C/C++ | [GitLab Advisories Community][gitlab] | ✅ | 1 month | [^1]: Intentional delay between vulnerability disclosure and registration in the DB diff --git a/docs/docs/vulnerability/detection/language.md b/docs/docs/vulnerability/detection/language.md index 81c9c4b1288..65422f68454 100644 --- a/docs/docs/vulnerability/detection/language.md +++ b/docs/docs/vulnerability/detection/language.md @@ -26,6 +26,7 @@ | | go.mod[^7] | - | - | ✅ | ✅ | included | | Rust | Cargo.lock | ✅ | ✅ | ✅ | ✅ | included | | | Binaries built with [cargo-auditable](https://github.com/rust-secure-code/cargo-auditable) | ✅ | ✅ | - | - | excluded +| C/C++ | conan.lock[^12] | - | - | ✅ | ✅ | excluded | The path of these files does not matter. @@ -42,3 +43,4 @@ Example: [Dockerfile](https://github.com/aquasecurity/trivy-ci-test/blob/main/Do [^9]: ✅ means "enabled" and `-` means "disabled" in the rootfs scanning [^10]: ✅ means "enabled" and `-` means "disabled" in the filesystem scanning [^11]: ✅ means "enabled" and `-` means "disabled" in the git repository scanning +[^12]: To scan a filename other than the default filename(`conan.lock`) use [file-patterns](../examples/others.md#file-patterns) \ No newline at end of file diff --git a/go.mod b/go.mod index aed2118ab46..57447a1870d 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/NYTimes/gziphandler v1.1.1 github.com/alicebob/miniredis/v2 v2.23.0 github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986 - github.com/aquasecurity/go-dep-parser v0.0.0-20220830123424-46cde9383d60 + github.com/aquasecurity/go-dep-parser v0.0.0-20220904090510-d2cb7a409fe8 github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798 github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 diff --git a/go.sum b/go.sum index ac103fe7ae7..41e2e6ec371 100644 --- a/go.sum +++ b/go.sum @@ -206,8 +206,8 @@ github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986 h1:2a30 github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986/go.mod h1:NT+jyeCzXk6vXR5MTkdn4z64TgGfE5HMLC8qfj5unl8= github.com/aquasecurity/defsec v0.71.9 h1:eo244v1RQzziClY9xXyVftPibE0fddXbTtkvH52/slU= github.com/aquasecurity/defsec v0.71.9/go.mod h1:2jYgkIi3UFbkrbtpnr3Cu49JZ3MGuLMJAhyh63jV1I4= -github.com/aquasecurity/go-dep-parser v0.0.0-20220830123424-46cde9383d60 h1:lBkhapZtunGpC8yu2fjGvGXUNbB2pNgmn5XPuHrPxnw= -github.com/aquasecurity/go-dep-parser v0.0.0-20220830123424-46cde9383d60/go.mod h1:6G1Y5nht5TL9kr1SzmrdE8PrmbNXo9nHx3qFR3qURg0= +github.com/aquasecurity/go-dep-parser v0.0.0-20220904090510-d2cb7a409fe8 h1:8jcz2qlLrsNDT/406nXMsi87Hsv/v1fw8SMbSpRhVP0= +github.com/aquasecurity/go-dep-parser v0.0.0-20220904090510-d2cb7a409fe8/go.mod h1:6G1Y5nht5TL9kr1SzmrdE8PrmbNXo9nHx3qFR3qURg0= github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce h1:QgBRgJvtEOBtUXilDb1MLi1p1MWoyFDXAu5DEUl5nwM= github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce/go.mod h1:HXgVzOPvXhVGLJs4ZKO817idqr/xhwsTcj17CLYY74s= github.com/aquasecurity/go-mock-aws v0.0.0-20220726154943-99847deb62b0 h1:tihCUjLWkF0b1SAjAKcFltUs3SpsqGrLtI+Frye0D10= diff --git a/integration/fs_test.go b/integration/fs_test.go index b4552c30d5a..d1b5f58e3b3 100644 --- a/integration/fs_test.go +++ b/integration/fs_test.go @@ -81,6 +81,15 @@ func TestFilesystem(t *testing.T) { }, golden: "testdata/gradle.json.golden", }, + { + name: "conan", + args: args{ + securityChecks: "vuln", + listAllPkgs: true, + input: "testdata/fixtures/fs/conan", + }, + golden: "testdata/conan.json.golden", + }, { name: "dockerfile", args: args{ diff --git a/integration/integration_test.go b/integration/integration_test.go index 2c188aa13de..95b5c0cb509 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -103,7 +103,6 @@ func readReport(t *testing.T, filePath string) types.Report { // We don't compare repo tags because the archive doesn't support it report.Metadata.RepoTags = nil - report.Metadata.RepoDigests = nil for i, result := range report.Results { diff --git a/integration/testdata/conan.json.golden b/integration/testdata/conan.json.golden new file mode 100644 index 00000000000..b9676e3eee3 --- /dev/null +++ b/integration/testdata/conan.json.golden @@ -0,0 +1,76 @@ +{ + "SchemaVersion": 2, + "ArtifactName": "testdata/fixtures/fs/conan", + "ArtifactType": "filesystem", + "Results": [ + { + "Target": "conan.lock", + "Class": "lang-pkgs", + "Type": "conan", + "Packages": [ + { + "ID": "bzip2/1.0.8", + "Name": "bzip2", + "Version": "1.0.8", + "Indirect": true + }, + { + "ID": "expat/2.4.8", + "Name": "expat", + "Version": "2.4.8", + "Indirect": true + }, + { + "ID": "openssl/1.1.1q", + "Name": "openssl", + "Version": "1.1.1q", + "Indirect": true + }, + { + "ID": "pcre/8.43", + "Name": "pcre", + "Version": "8.43", + "Indirect": true, + "DependsOn": [ + "bzip2/1.0.8", + "zlib/1.2.12" + ] + }, + { + "ID": "poco/1.9.4", + "Name": "poco", + "Version": "1.9.4", + "DependsOn": [ + "pcre/8.43", + "zlib/1.2.12", + "expat/2.4.8", + "sqlite3/3.39.2", + "openssl/1.1.1q" + ] + }, + { + "ID": "sqlite3/3.39.2", + "Name": "sqlite3", + "Version": "3.39.2", + "Indirect": true + }, + { + "ID": "zlib/1.2.12", + "Name": "zlib", + "Version": "1.2.12", + "Indirect": true + } + ], + "Vulnerabilities": [ + { + "VulnerabilityID": "CVE-2020-14155", + "PkgID": "pcre/8.43", + "PkgName": "pcre", + "InstalledVersion": "8.43", + "FixedVersion": "8.45", + "Severity": "UNKNOWN" + } + ] + } + ] +} diff --git a/integration/testdata/fixtures/db/conan.yaml b/integration/testdata/fixtures/db/conan.yaml new file mode 100644 index 00000000000..9d7089ee8f7 --- /dev/null +++ b/integration/testdata/fixtures/db/conan.yaml @@ -0,0 +1,10 @@ +- bucket: conan::GitLab Advisory Database Community + pairs: + - bucket: pcre + pairs: + - key: CVE-2020-14155 + value: + PatchedVersions: + - "8.45" + VulnerableVersions: + - "<8.44" diff --git a/integration/testdata/fixtures/db/vulnerability.yaml b/integration/testdata/fixtures/db/vulnerability.yaml index cf29e03d7b8..7d99784b8e1 100644 --- a/integration/testdata/fixtures/db/vulnerability.yaml +++ b/integration/testdata/fixtures/db/vulnerability.yaml @@ -1206,4 +1206,27 @@ - "https://github.com/advisories/GHSA-36p3-wjmg-h94x", PublishedDate: "2022-04-01T23:15:00Z" LastModifiedDate: "2022-05-19T14:21:00Z" - + - key: CVE-2020-14155 + value: + Title: "pcre: Integer overflow when parsing callout numeric arguments" + Description: "libpcre in PCRE before 8.44 allows an integer overflow via a large number after a (?C substring." + Severity: MEDIUM + CweIDs: + - CWE-190 + VendorSeverity: + alma: 1 + nvd: 2 + CVSS: + nvd: + V2Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P" + V3Vector: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L" + V2Score: 5 + V3Score: 5.3 + redhat: + V3Vector: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L" + V3Score: 5.3 + References: + - "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-14155", + - "https://nvd.nist.gov/vuln/detail/CVE-2020-14155" + PublishedDate: "2020-06-15T17:15:00Z" + LastModifiedDate: "2022-04-28T15:06:00Z" \ No newline at end of file diff --git a/integration/testdata/fixtures/fs/conan/conan.lock b/integration/testdata/fixtures/fs/conan/conan.lock new file mode 100644 index 00000000000..3c066117ed5 --- /dev/null +++ b/integration/testdata/fixtures/fs/conan/conan.lock @@ -0,0 +1,77 @@ +{ + "graph_lock": { + "nodes": { + "0": { + "options": "bzip2:build_executable=True\nbzip2:fPIC=True\nbzip2:shared=False\nexpat:char_type=char\nexpat:fPIC=True\nexpat:shared=False\nopenssl:386=False\nopenssl:enable_weak_ssl_ciphers=False\nopenssl:fPIC=True\nopenssl:no_aria=False\nopenssl:no_asm=False\nopenssl:no_async=False\nopenssl:no_bf=False\nopenssl:no_blake2=False\nopenssl:no_camellia=False\nopenssl:no_cast=False\nopenssl:no_chacha=False\nopenssl:no_cms=False\nopenssl:no_comp=False\nopenssl:no_ct=False\nopenssl:no_deprecated=False\nopenssl:no_des=False\nopenssl:no_dgram=False\nopenssl:no_dh=False\nopenssl:no_dsa=False\nopenssl:no_dso=False\nopenssl:no_ec=False\nopenssl:no_ecdh=False\nopenssl:no_ecdsa=False\nopenssl:no_engine=False\nopenssl:no_filenames=False\nopenssl:no_gost=False\nopenssl:no_hmac=False\nopenssl:no_idea=False\nopenssl:no_md4=False\nopenssl:no_md5=False\nopenssl:no_mdc2=False\nopenssl:no_ocsp=False\nopenssl:no_pinshared=False\nopenssl:no_rc2=False\nopenssl:no_rfc3779=False\nopenssl:no_rmd160=False\nopenssl:no_rsa=False\nopenssl:no_seed=False\nopenssl:no_sha=False\nopenssl:no_sm2=False\nopenssl:no_sm3=False\nopenssl:no_sm4=False\nopenssl:no_sock=False\nopenssl:no_srp=False\nopenssl:no_srtp=False\nopenssl:no_sse2=False\nopenssl:no_ssl=False\nopenssl:no_ssl3=False\nopenssl:no_stdio=False\nopenssl:no_tests=False\nopenssl:no_threads=False\nopenssl:no_tls1=False\nopenssl:no_ts=False\nopenssl:no_whirlpool=False\nopenssl:openssldir=None\nopenssl:shared=False\npcre:build_pcre_16=True\npcre:build_pcre_32=True\npcre:build_pcre_8=True\npcre:build_pcrecpp=False\npcre:build_pcregrep=True\npcre:fPIC=True\npcre:shared=False\npcre:with_bzip2=True\npcre:with_jit=False\npcre:with_stack_for_recursion=True\npcre:with_unicode_properties=True\npcre:with_utf=True\npcre:with_zlib=True\npoco:enable_active_record=deprecated\npoco:enable_apacheconnector=False\npoco:enable_cppparser=False\npoco:enable_crypto=True\npoco:enable_data=True\npoco:enable_data_odbc=False\npoco:enable_data_sqlite=True\npoco:enable_encodings=True\npoco:enable_fork=True\npoco:enable_json=True\npoco:enable_mongodb=True\npoco:enable_net=True\npoco:enable_netssl=True\npoco:enable_pagecompiler=False\npoco:enable_pagecompiler_file2page=False\npoco:enable_pdf=False\npoco:enable_pocodoc=False\npoco:enable_redis=True\npoco:enable_sevenzip=False\npoco:enable_util=True\npoco:enable_xml=True\npoco:enable_zip=True\npoco:fPIC=True\npoco:shared=False\nsqlite3:build_executable=True\nsqlite3:disable_gethostuuid=False\nsqlite3:enable_column_metadata=True\nsqlite3:enable_dbpage_vtab=False\nsqlite3:enable_dbstat_vtab=False\nsqlite3:enable_default_secure_delete=False\nsqlite3:enable_default_vfs=True\nsqlite3:enable_explain_comments=False\nsqlite3:enable_fts3=False\nsqlite3:enable_fts3_parenthesis=False\nsqlite3:enable_fts4=False\nsqlite3:enable_fts5=False\nsqlite3:enable_json1=False\nsqlite3:enable_math_functions=True\nsqlite3:enable_preupdate_hook=False\nsqlite3:enable_rtree=True\nsqlite3:enable_soundex=False\nsqlite3:enable_unlock_notify=True\nsqlite3:fPIC=True\nsqlite3:max_blob_size=None\nsqlite3:max_column=None\nsqlite3:max_variable_number=None\nsqlite3:omit_deprecated=False\nsqlite3:omit_load_extension=False\nsqlite3:shared=False\nsqlite3:threadsafe=1\nsqlite3:use_alloca=False\nzlib:fPIC=True\nzlib:shared=False", + "requires": [ + "1" + ], + "path": "../conanfile.txt", + "context": "host" + }, + "1": { + "ref": "poco/1.9.4", + "options": "enable_active_record=deprecated\nenable_apacheconnector=False\nenable_cppparser=False\nenable_crypto=True\nenable_data=True\nenable_data_odbc=False\nenable_data_sqlite=True\nenable_encodings=True\nenable_fork=True\nenable_json=True\nenable_mongodb=True\nenable_net=True\nenable_netssl=True\nenable_pagecompiler=False\nenable_pagecompiler_file2page=False\nenable_pdf=False\nenable_pocodoc=False\nenable_redis=True\nenable_sevenzip=False\nenable_util=True\nenable_xml=True\nenable_zip=True\nfPIC=True\nshared=False\nbzip2:build_executable=True\nbzip2:fPIC=True\nbzip2:shared=False\nexpat:char_type=char\nexpat:fPIC=True\nexpat:shared=False\nopenssl:386=False\nopenssl:enable_weak_ssl_ciphers=False\nopenssl:fPIC=True\nopenssl:no_aria=False\nopenssl:no_asm=False\nopenssl:no_async=False\nopenssl:no_bf=False\nopenssl:no_blake2=False\nopenssl:no_camellia=False\nopenssl:no_cast=False\nopenssl:no_chacha=False\nopenssl:no_cms=False\nopenssl:no_comp=False\nopenssl:no_ct=False\nopenssl:no_deprecated=False\nopenssl:no_des=False\nopenssl:no_dgram=False\nopenssl:no_dh=False\nopenssl:no_dsa=False\nopenssl:no_dso=False\nopenssl:no_ec=False\nopenssl:no_ecdh=False\nopenssl:no_ecdsa=False\nopenssl:no_engine=False\nopenssl:no_filenames=False\nopenssl:no_gost=False\nopenssl:no_hmac=False\nopenssl:no_idea=False\nopenssl:no_md4=False\nopenssl:no_md5=False\nopenssl:no_mdc2=False\nopenssl:no_ocsp=False\nopenssl:no_pinshared=False\nopenssl:no_rc2=False\nopenssl:no_rfc3779=False\nopenssl:no_rmd160=False\nopenssl:no_rsa=False\nopenssl:no_seed=False\nopenssl:no_sha=False\nopenssl:no_sm2=False\nopenssl:no_sm3=False\nopenssl:no_sm4=False\nopenssl:no_sock=False\nopenssl:no_srp=False\nopenssl:no_srtp=False\nopenssl:no_sse2=False\nopenssl:no_ssl=False\nopenssl:no_ssl3=False\nopenssl:no_stdio=False\nopenssl:no_tests=False\nopenssl:no_threads=False\nopenssl:no_tls1=False\nopenssl:no_ts=False\nopenssl:no_whirlpool=False\nopenssl:openssldir=None\nopenssl:shared=False\npcre:build_pcre_16=True\npcre:build_pcre_32=True\npcre:build_pcre_8=True\npcre:build_pcrecpp=False\npcre:build_pcregrep=True\npcre:fPIC=True\npcre:shared=False\npcre:with_bzip2=True\npcre:with_jit=False\npcre:with_stack_for_recursion=True\npcre:with_unicode_properties=True\npcre:with_utf=True\npcre:with_zlib=True\nsqlite3:build_executable=True\nsqlite3:disable_gethostuuid=False\nsqlite3:enable_column_metadata=True\nsqlite3:enable_dbpage_vtab=False\nsqlite3:enable_dbstat_vtab=False\nsqlite3:enable_default_secure_delete=False\nsqlite3:enable_default_vfs=True\nsqlite3:enable_explain_comments=False\nsqlite3:enable_fts3=False\nsqlite3:enable_fts3_parenthesis=False\nsqlite3:enable_fts4=False\nsqlite3:enable_fts5=False\nsqlite3:enable_json1=False\nsqlite3:enable_math_functions=True\nsqlite3:enable_preupdate_hook=False\nsqlite3:enable_rtree=True\nsqlite3:enable_soundex=False\nsqlite3:enable_unlock_notify=True\nsqlite3:fPIC=True\nsqlite3:max_blob_size=None\nsqlite3:max_column=None\nsqlite3:max_variable_number=None\nsqlite3:omit_deprecated=False\nsqlite3:omit_load_extension=False\nsqlite3:shared=False\nsqlite3:threadsafe=1\nsqlite3:use_alloca=False\nzlib:fPIC=True\nzlib:shared=False", + "package_id": "c3c2e0fbf9199382c510453d5fa86501149cf57a", + "prev": "0", + "requires": [ + "2", + "4", + "5", + "6", + "7" + ], + "context": "host" + }, + "2": { + "ref": "pcre/8.43", + "options": "build_pcre_16=True\nbuild_pcre_32=True\nbuild_pcre_8=True\nbuild_pcrecpp=False\nbuild_pcregrep=True\nfPIC=True\nshared=False\nwith_bzip2=True\nwith_jit=False\nwith_stack_for_recursion=True\nwith_unicode_properties=True\nwith_utf=True\nwith_zlib=True\nbzip2:build_executable=True\nbzip2:fPIC=True\nbzip2:shared=False\nzlib:fPIC=True\nzlib:shared=False", + "package_id": "fab187555fa87e54b51a5e8e8ff95b0f5855d00b", + "prev": "0", + "requires": [ + "3", + "4" + ], + "context": "host" + }, + "3": { + "ref": "bzip2/1.0.8", + "options": "build_executable=True\nfPIC=True\nshared=False", + "package_id": "3df6ebb8a308d309e882b21988fd9ea103560e16", + "prev": "0", + "context": "host" + }, + "4": { + "ref": "zlib/1.2.12", + "options": "fPIC=True\nshared=False", + "package_id": "76f87539fc90ff313e0b3182641a9bb558a717d2", + "prev": "0", + "context": "host" + }, + "5": { + "ref": "expat/2.4.8", + "options": "char_type=char\nfPIC=True\nshared=False", + "package_id": "b025735bb0d121754b0b4aaae6c02d3b9546c56f", + "prev": "0", + "context": "host" + }, + "6": { + "ref": "sqlite3/3.39.2", + "options": "build_executable=True\ndisable_gethostuuid=False\nenable_column_metadata=True\nenable_dbpage_vtab=False\nenable_dbstat_vtab=False\nenable_default_secure_delete=False\nenable_default_vfs=True\nenable_explain_comments=False\nenable_fts3=False\nenable_fts3_parenthesis=False\nenable_fts4=False\nenable_fts5=False\nenable_json1=False\nenable_math_functions=True\nenable_preupdate_hook=False\nenable_rtree=True\nenable_soundex=False\nenable_unlock_notify=True\nfPIC=True\nmax_blob_size=None\nmax_column=None\nmax_variable_number=None\nomit_deprecated=False\nomit_load_extension=False\nshared=False\nthreadsafe=1\nuse_alloca=False", + "package_id": "bc01b0a8d9a484b3b4226ef647e2ba7dd5b627ed", + "prev": "0", + "context": "host" + }, + "7": { + "ref": "openssl/1.1.1q", + "options": "386=False\nenable_weak_ssl_ciphers=False\nfPIC=True\nno_aria=False\nno_asm=False\nno_async=False\nno_bf=False\nno_blake2=False\nno_camellia=False\nno_cast=False\nno_chacha=False\nno_cms=False\nno_comp=False\nno_ct=False\nno_deprecated=False\nno_des=False\nno_dgram=False\nno_dh=False\nno_dsa=False\nno_dso=False\nno_ec=False\nno_ecdh=False\nno_ecdsa=False\nno_engine=False\nno_filenames=False\nno_gost=False\nno_hmac=False\nno_idea=False\nno_md4=False\nno_md5=False\nno_mdc2=False\nno_ocsp=False\nno_pinshared=False\nno_rc2=False\nno_rfc3779=False\nno_rmd160=False\nno_rsa=False\nno_seed=False\nno_sha=False\nno_sm2=False\nno_sm3=False\nno_sm4=False\nno_sock=False\nno_srp=False\nno_srtp=False\nno_sse2=False\nno_ssl=False\nno_ssl3=False\nno_stdio=False\nno_tests=False\nno_threads=False\nno_tls1=False\nno_ts=False\nno_whirlpool=False\nopenssldir=None\nshared=False", + "package_id": "76f87539fc90ff313e0b3182641a9bb558a717d2", + "prev": "0", + "context": "host" + } + }, + "revisions_enabled": false + }, + "version": "0.4", + "profile_host": "[settings]\narch=x86_64\narch_build=x86_64\nbuild_type=Release\ncompiler=gcc\ncompiler.libcxx=libstdc++\ncompiler.version=5\nos=Linux\nos_build=Linux\n[options]\n[build_requires]\n[env]\n" +} \ No newline at end of file diff --git a/pkg/detector/library/detect.go b/pkg/detector/library/detect.go index 7c69ac85645..2f1df1d1856 100644 --- a/pkg/detector/library/detect.go +++ b/pkg/detector/library/detect.go @@ -11,7 +11,7 @@ import ( func Detect(libType string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) { driver, err := NewDriver(libType) if err != nil { - return nil, xerrors.Errorf("failed to new driver: %w", err) + return nil, xerrors.Errorf("failed to initialize a driver: %w", err) } vulns, err := detect(driver, pkgs) diff --git a/pkg/detector/library/driver.go b/pkg/detector/library/driver.go index 3cf5439b176..b3529a1d591 100644 --- a/pkg/detector/library/driver.go +++ b/pkg/detector/library/driver.go @@ -49,6 +49,11 @@ func NewDriver(libType string) (Driver, error) { case ftypes.Pipenv, ftypes.Poetry, ftypes.Pip, ftypes.PythonPkg: ecosystem = vulnerability.Pip comparer = pep440.Comparer{} + case ftypes.Conan: + ecosystem = vulnerability.Conan + // Only semver can be used for version ranges + // https://docs.conan.io/en/latest/versioning/version_ranges.html + comparer = compare.GenericComparer{} default: return Driver{}, xerrors.Errorf("unsupported type %s", libType) } diff --git a/pkg/fanal/analyzer/all/import.go b/pkg/fanal/analyzer/all/import.go index f3009ee68ee..a7a80aa56b9 100644 --- a/pkg/fanal/analyzer/all/import.go +++ b/pkg/fanal/analyzer/all/import.go @@ -4,6 +4,7 @@ import ( _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/buildinfo" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/command/apk" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/all" + _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/c/conan" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/dotnet/deps" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/dotnet/nuget" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/golang/binary" diff --git a/pkg/fanal/analyzer/const.go b/pkg/fanal/analyzer/const.go index 33a46cea361..ad557e3f9e4 100644 --- a/pkg/fanal/analyzer/const.go +++ b/pkg/fanal/analyzer/const.go @@ -71,6 +71,9 @@ const ( TypeGoBinary Type = "gobinary" TypeGoMod Type = "gomod" + // C/C++ + TypeConanLock Type = "conan-lock" + // ============ // Image Config // ============ @@ -116,13 +119,13 @@ var ( TypeLanguages = []Type{ TypeBundler, TypeGemSpec, TypeCargo, TypeComposer, TypeJar, TypePom, TypeGradleLock, TypeNpmPkgLock, TypeNodePkg, TypeYarn, TypePnpm, TypeNuget, TypeDotNetDeps, - TypePythonPkg, TypePip, TypePipenv, TypePoetry, TypeGoBinary, TypeGoMod, TypeRustBinary, + TypePythonPkg, TypePip, TypePipenv, TypePoetry, TypeGoBinary, TypeGoMod, TypeRustBinary, TypeConanLock, } // TypeLockfiles has all lock file analyzers TypeLockfiles = []Type{ TypeBundler, TypeNpmPkgLock, TypeYarn, - TypePnpm, TypePip, TypePipenv, TypePoetry, TypeGoMod, TypePom, TypeGradleLock, + TypePnpm, TypePip, TypePipenv, TypePoetry, TypeGoMod, TypePom, TypeConanLock, TypeGradleLock, } // TypeIndividualPkgs has all analyzers for individual packages diff --git a/pkg/fanal/analyzer/language/c/conan/conan.go b/pkg/fanal/analyzer/language/c/conan/conan.go new file mode 100644 index 00000000000..3f144265214 --- /dev/null +++ b/pkg/fanal/analyzer/language/c/conan/conan.go @@ -0,0 +1,48 @@ +package conan + +import ( + "context" + "os" + + "golang.org/x/xerrors" + + "github.com/aquasecurity/go-dep-parser/pkg/c/conan" + "github.com/aquasecurity/trivy/pkg/fanal/analyzer" + "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language" + "github.com/aquasecurity/trivy/pkg/fanal/types" +) + +func init() { + analyzer.RegisterAnalyzer(&conanLockAnalyzer{}) +} + +const ( + version = 1 +) + +// conanLockAnalyzer analyzes conan.lock +type conanLockAnalyzer struct{} + +func (a conanLockAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput) (*analyzer.AnalysisResult, error) { + p := conan.NewParser() + res, err := language.Analyze(types.Conan, input.FilePath, input.Content, p) + if err != nil { + return nil, xerrors.Errorf("%s parse error: %w", input.FilePath, err) + } + return res, nil +} + +func (a conanLockAnalyzer) Required(_ string, fileInfo os.FileInfo) bool { + // Lock file name can be anything + // cf. https://docs.conan.io/en/latest/versioning/lockfiles/introduction.html#locking-dependencies + // By default, we only check the default filename - `conan.lock`. + return fileInfo.Name() == types.ConanLock +} + +func (a conanLockAnalyzer) Type() analyzer.Type { + return analyzer.TypeConanLock +} + +func (a conanLockAnalyzer) Version() int { + return version +} diff --git a/pkg/fanal/analyzer/language/c/conan/conan_test.go b/pkg/fanal/analyzer/language/c/conan/conan_test.go new file mode 100644 index 00000000000..9e4cf9f92d0 --- /dev/null +++ b/pkg/fanal/analyzer/language/c/conan/conan_test.go @@ -0,0 +1,118 @@ +package conan + +import ( + "os" + "path/filepath" + "sort" + "testing" + + "github.com/aquasecurity/trivy/pkg/fanal/analyzer" + "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func Test_conanLockAnalyzer_Analyze(t *testing.T) { + tests := []struct { + name string + inputFile string + want *analyzer.AnalysisResult + }{ + { + name: "happy path", + inputFile: "testdata/happy.lock", + want: &analyzer.AnalysisResult{ + Applications: []types.Application{ + { + Type: types.Conan, + FilePath: "testdata/happy.lock", + Libraries: []types.Package{ + { + ID: "openssl/3.0.5", + Name: "openssl", + Version: "3.0.5", + DependsOn: []string{ + "zlib/1.2.12", + }, + }, + { + ID: "zlib/1.2.12", + Name: "zlib", + Version: "1.2.12", + Indirect: true, + }, + }, + }, + }, + }, + }, + { + name: "empty file", + inputFile: "testdata/empty.lock", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + f, err := os.Open(tt.inputFile) + require.NoError(t, err) + defer f.Close() + + a := conanLockAnalyzer{} + got, err := a.Analyze(nil, analyzer.AnalysisInput{ + FilePath: tt.inputFile, + Content: f, + }) + + if got != nil { + for _, app := range got.Applications { + sort.Slice(app.Libraries, func(i, j int) bool { + return app.Libraries[i].ID < app.Libraries[j].ID + }) + } + } + + assert.NoError(t, err) + assert.Equal(t, tt.want, got) + }) + } +} + +func Test_conanLockAnalyzer_Required(t *testing.T) { + tests := []struct { + name string + filePath string + want bool + }{ + { + name: "default name", + filePath: "conan.lock", + want: true, + }, + { + name: "name with prefix", + filePath: "pkga_deps.lock", + want: false, + }, + { + name: "txt", + filePath: "test.txt", + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + dir := t.TempDir() + f, err := os.Create(filepath.Join(dir, tt.filePath)) + require.NoError(t, err) + defer f.Close() + + fi, err := f.Stat() + require.NoError(t, err) + + a := conanLockAnalyzer{} + got := a.Required("", fi) + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/pkg/fanal/analyzer/language/c/conan/testdata/empty.lock b/pkg/fanal/analyzer/language/c/conan/testdata/empty.lock new file mode 100644 index 00000000000..106ca0aa06b --- /dev/null +++ b/pkg/fanal/analyzer/language/c/conan/testdata/empty.lock @@ -0,0 +1,14 @@ +{ + "graph_lock": { + "nodes": { + "0": { + "options": "o", + "path": "conanfile.txt", + "context": "host" + } + }, + "revisions_enabled": false + }, + "version": "0.4", + "profile_host": "[settings]\narch=x86_64\narch_build=x86_64\nbuild_type=Release\ncompiler=gcc\ncompiler.libcxx=libstdc++\ncompiler.version=9\nos=Linux\nos_build=Linux\n[options]\n[build_requires]\n[env]\n" +} \ No newline at end of file diff --git a/pkg/fanal/analyzer/language/c/conan/testdata/happy.lock b/pkg/fanal/analyzer/language/c/conan/testdata/happy.lock new file mode 100644 index 00000000000..eb17995310e --- /dev/null +++ b/pkg/fanal/analyzer/language/c/conan/testdata/happy.lock @@ -0,0 +1,34 @@ +{ + "graph_lock": { + "nodes": { + "0": { + "options": "o", + "requires": [ + "1" + ], + "path": "conanfile.txt", + "context": "host" + }, + "1": { + "ref": "openssl/3.0.5", + "options": "", + "requires": [ + "2" + ], + "package_id": "", + "prev": "0", + "context": "host" + }, + "2": { + "ref": "zlib/1.2.12", + "options": "", + "package_id": "", + "prev": "0", + "context": "host" + } + }, + "revisions_enabled": false + }, + "version": "0.4", + "profile_host": "[settings]\narch=x86_64\narch_build=x86_64\nbuild_type=Release\ncompiler=gcc\ncompiler.libcxx=libstdc++\ncompiler.version=9\nos=Linux\nos_build=Linux\n[options]\n[build_requires]\n[env]\n" +} \ No newline at end of file diff --git a/pkg/fanal/types/const.go b/pkg/fanal/types/const.go index 0280c5ce381..a2d2e73e015 100644 --- a/pkg/fanal/types/const.go +++ b/pkg/fanal/types/const.go @@ -28,6 +28,7 @@ const ( GoModule = "gomod" JavaScript = "javascript" RustBinary = "rustbinary" + Conan = "conan" // Config files YAML = "yaml" @@ -66,4 +67,6 @@ const ( GemfileLock = "Gemfile.lock" CargoLock = "Cargo.lock" + + ConanLock = "conan.lock" )