From fbd8a13d54105159b26a1d70235f062784fa6cf5 Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Tue, 10 Jan 2023 14:34:53 +0300 Subject: [PATCH] feat: add support pubspec.lock files for dart (#3344) Co-authored-by: knqyf263 --- .github/workflows/semantic-pr.yaml | 1 + docs/community/contribute/pr.md | 1 + .../vulnerability/detection/data-source.md | 2 + docs/docs/vulnerability/detection/language.md | 1 + go.mod | 2 +- go.sum | 4 +- integration/fs_test.go | 9 ++ .../testdata/fixtures/db/data-source.yaml | 5 + integration/testdata/fixtures/db/pub.yaml | 10 ++ .../testdata/fixtures/db/vulnerability.yaml | 23 ++++ .../testdata/fixtures/fs/pubspec/pubspec.lock | 20 +++ integration/testdata/pubspec.lock.json.golden | 77 ++++++++++++ pkg/detector/library/driver.go | 3 + pkg/fanal/analyzer/all/import.go | 1 + pkg/fanal/analyzer/const.go | 7 +- .../analyzer/language/dart/pub/pubspec.go | 46 +++++++ .../language/dart/pub/pubspec_test.go | 115 ++++++++++++++++++ .../language/dart/pub/testdata/broken.lock | 1 + .../language/dart/pub/testdata/empty.lock | 6 + .../language/dart/pub/testdata/happy.lock | 25 ++++ pkg/fanal/types/const.go | 3 + pkg/purl/purl.go | 9 +- pkg/purl/purl_test.go | 27 ++++ 23 files changed, 391 insertions(+), 7 deletions(-) create mode 100644 integration/testdata/fixtures/db/pub.yaml create mode 100644 integration/testdata/fixtures/fs/pubspec/pubspec.lock create mode 100644 integration/testdata/pubspec.lock.json.golden create mode 100644 pkg/fanal/analyzer/language/dart/pub/pubspec.go create mode 100644 pkg/fanal/analyzer/language/dart/pub/pubspec_test.go create mode 100644 pkg/fanal/analyzer/language/dart/pub/testdata/broken.lock create mode 100644 pkg/fanal/analyzer/language/dart/pub/testdata/empty.lock create mode 100644 pkg/fanal/analyzer/language/dart/pub/testdata/happy.lock diff --git a/.github/workflows/semantic-pr.yaml b/.github/workflows/semantic-pr.yaml index 200e7ce1ed..60e282cd28 100644 --- a/.github/workflows/semantic-pr.yaml +++ b/.github/workflows/semantic-pr.yaml @@ -71,6 +71,7 @@ jobs: c c++ elixir + dart os lang diff --git a/docs/community/contribute/pr.md b/docs/community/contribute/pr.md index 828d31d984..1d6c6f4726 100644 --- a/docs/community/contribute/pr.md +++ b/docs/community/contribute/pr.md @@ -81,6 +81,7 @@ language: - java - go - elixir +- dart vuln: diff --git a/docs/docs/vulnerability/detection/data-source.md b/docs/docs/vulnerability/detection/data-source.md index bd019bc7c8..367a02e061 100644 --- a/docs/docs/vulnerability/detection/data-source.md +++ b/docs/docs/vulnerability/detection/data-source.md @@ -37,6 +37,7 @@ | Rust | [Open Source Vulnerabilities (crates.io)][rust-osv] | ✅ | - | | .NET | [GitHub Advisory Database (NuGet)][dotnet-ghsa] | ✅ | - | | C/C++ | [GitLab Advisories Community][gitlab] | ✅ | 1 month | +| Dart | [GitHub Advisory Database (Pub)][pub-ghsa] | ✅ | - | | Elixir | [GitHub Advisory Database (Erlang)][erlang-ghsa] | ✅ | | [^1]: Intentional delay between vulnerability disclosure and registration in the DB @@ -79,6 +80,7 @@ The severity is from the selected data source. If the data source does not provi [nodejs-ghsa]: https://github.com/advisories?query=ecosystem%3Anpm [java-ghsa]: https://github.com/advisories?query=ecosystem%3Amaven [dotnet-ghsa]: https://github.com/advisories?query=ecosystem%3Anuget +[pub-ghsa]: https://github.com/advisories?query=ecosystem%3Apub [erlang-ghsa]: https://github.com/advisories?query=ecosystem%3Aerlang [php]: https://github.com/FriendsOfPHP/security-advisories diff --git a/docs/docs/vulnerability/detection/language.md b/docs/docs/vulnerability/detection/language.md index 9a584a9c55..1b733f541d 100644 --- a/docs/docs/vulnerability/detection/language.md +++ b/docs/docs/vulnerability/detection/language.md @@ -28,6 +28,7 @@ | | Binaries built with [cargo-auditable](https://github.com/rust-secure-code/cargo-auditable) | ✅ | ✅ | - | - | excluded | - | | C/C++ | conan.lock[^13] | - | - | ✅ | ✅ | excluded | - | | Elixir | mix.lock[^13] | - | - | ✅ | ✅ | excluded | ✅ | +| Dart | pubspec.lock | ✅ | ✅ | - | - | included | - | The path of these files does not matter. diff --git a/go.mod b/go.mod index 12f5f3b44d..a494205e73 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/aquasecurity/table v1.8.0 github.com/aquasecurity/testdocker v0.0.0-20210911155206-e1e85f5a1516 github.com/aquasecurity/tml v0.6.1 - github.com/aquasecurity/trivy-db v0.0.0-20221227141502-af78ecb7db4c + github.com/aquasecurity/trivy-db v0.0.0-20230105123735-5ce110fc82e1 github.com/aquasecurity/trivy-kubernetes v0.3.1-0.20221021174315-8d74450b4506 github.com/aws/aws-sdk-go v1.44.171 github.com/aws/aws-sdk-go-v2 v1.17.1 diff --git a/go.sum b/go.sum index 1afe384efb..f42c1a886b 100644 --- a/go.sum +++ b/go.sum @@ -217,8 +217,8 @@ github.com/aquasecurity/testdocker v0.0.0-20210911155206-e1e85f5a1516 h1:moQmzbp github.com/aquasecurity/testdocker v0.0.0-20210911155206-e1e85f5a1516/go.mod h1:gTd97VdQ0rg8Mkiic3rPgNOQdprZ7feTAhiD5mGQjgM= github.com/aquasecurity/tml v0.6.1 h1:y2ZlGSfrhnn7t4ZJ/0rotuH+v5Jgv6BDDO5jB6A9gwo= github.com/aquasecurity/tml v0.6.1/go.mod h1:OnYMWY5lvI9ejU7yH9LCberWaaTBW7hBFsITiIMY2yY= -github.com/aquasecurity/trivy-db v0.0.0-20221227141502-af78ecb7db4c h1:CgJiXxVxgFOQ4btP97LEYqEHnx++FRpf2IJEXJV+xHs= -github.com/aquasecurity/trivy-db v0.0.0-20221227141502-af78ecb7db4c/go.mod h1:/nULgnDeq/JMPMVwE1dmf4kWlYn++7VrM3O2naj4BHA= +github.com/aquasecurity/trivy-db v0.0.0-20230105123735-5ce110fc82e1 h1:3ANUmuIZlMpSmhd6ah3FWQuZxZQFdpRzlrn0p90zzVc= +github.com/aquasecurity/trivy-db v0.0.0-20230105123735-5ce110fc82e1/go.mod h1:/nULgnDeq/JMPMVwE1dmf4kWlYn++7VrM3O2naj4BHA= github.com/aquasecurity/trivy-kubernetes v0.3.1-0.20221021174315-8d74450b4506 h1:maijOWmI5Ec/R7V0wpXoqvQC7fTjQD+PbDktKIK1VXs= github.com/aquasecurity/trivy-kubernetes v0.3.1-0.20221021174315-8d74450b4506/go.mod h1:xXd1m0iRJrz3ISbOXVDaR4hCWoSrF4RbIfNTN4dTrjY= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= diff --git a/integration/fs_test.go b/integration/fs_test.go index 1a43baa0b8..349ce59e72 100644 --- a/integration/fs_test.go +++ b/integration/fs_test.go @@ -147,6 +147,15 @@ func TestFilesystem(t *testing.T) { }, golden: "testdata/cocoapods.json.golden", }, + { + name: "pubspec.lock", + args: args{ + securityChecks: "vuln", + listAllPkgs: true, + input: "testdata/fixtures/fs/pubspec", + }, + golden: "testdata/pubspec.lock.json.golden", + }, { name: "mix.lock", args: args{ diff --git a/integration/testdata/fixtures/db/data-source.yaml b/integration/testdata/fixtures/db/data-source.yaml index 2611842c21..818a566b4f 100644 --- a/integration/testdata/fixtures/db/data-source.yaml +++ b/integration/testdata/fixtures/db/data-source.yaml @@ -30,6 +30,11 @@ ID: "ghsa" Name: "GitHub Security Advisory RubyGems" URL: "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Arubygems" + - key: "pub::GitHub Security Advisory Pub" + value: + ID: "ghsa" + Name: "GitHub Security Advisory Pub" + URL: "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Apub" - key: "erlang::GitHub Security Advisory Erlang" value: ID: "ghsa" diff --git a/integration/testdata/fixtures/db/pub.yaml b/integration/testdata/fixtures/db/pub.yaml new file mode 100644 index 0000000000..603bc82cf8 --- /dev/null +++ b/integration/testdata/fixtures/db/pub.yaml @@ -0,0 +1,10 @@ +- bucket: pub::GitHub Security Advisory Pub + pairs: + - bucket: http + pairs: + - key: CVE-2020-35669 + value: + PatchedVersions: + - 0.13.3 + VulnerableVersions: + - "<= 0.13.3" \ No newline at end of file diff --git a/integration/testdata/fixtures/db/vulnerability.yaml b/integration/testdata/fixtures/db/vulnerability.yaml index b530008378..3e23702f20 100644 --- a/integration/testdata/fixtures/db/vulnerability.yaml +++ b/integration/testdata/fixtures/db/vulnerability.yaml @@ -1271,6 +1271,29 @@ - https://github.com/advisories/GHSA-p8f7-22gq-m7j9 PublishedDate: "2022-10-17T12:00:27Z" LastModifiedDate: "2022-10-18T18:01:44Z" + - key: CVE-2020-35669 + value: + Title: "http before 0.13.3 vulnerable to header injection" + Description: "An issue was discovered in the http package before 0.13.3 for Dart. If the attacker controls the HTTP method and the app is using Request directly, it's possible to achieve CRLF injection in an HTTP request via HTTP header injection. This issue has been addressed in commit abb2bb182 by validating request methods." + Severity: MEDIUM + VendorSeverity: + ghsa: 2 + CweIDs: + - CWE-74 + CVSS: + ghsa: + V3Vector: "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N" + V3Score: 6.1 + References: + - https://nvd.nist.gov/vuln/detail/CVE-2020-35669 + - https://github.com/dart-lang/http/issues/511 + - https://github.com/dart-lang/http/blob/master/CHANGELOG.md#0133 + - https://github.com/dart-lang/http/pull/512 + - https://github.com/dart-lang/http/commit/abb2bb182fbd7f03aafd1f889b902d7b3bdb8769 + - https://pub.dev/packages/http/changelog#0133 + - https://github.com/advisories/GHSA-4rgh-jx4f-qfcq + PublishedDate: "2022-05-24T17:37:16Z" + LastModifiedDate: "2022-10-06T20:26:08Z" - key: CVE-2022-22965 value: Title: "spring-framework: RCE via Data Binding on JDK 9+" diff --git a/integration/testdata/fixtures/fs/pubspec/pubspec.lock b/integration/testdata/fixtures/fs/pubspec/pubspec.lock new file mode 100644 index 0000000000..043c82efce --- /dev/null +++ b/integration/testdata/fixtures/fs/pubspec/pubspec.lock @@ -0,0 +1,20 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + http: + dependency: "direct main" + description: + name: http + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.13.2" + shelf: + dependency: transitive + description: + name: shelf + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.1" +sdks: + dart: ">=2.18.0 <3.0.0" + flutter: ">=3.3.0" \ No newline at end of file diff --git a/integration/testdata/pubspec.lock.json.golden b/integration/testdata/pubspec.lock.json.golden new file mode 100644 index 0000000000..f26e76b111 --- /dev/null +++ b/integration/testdata/pubspec.lock.json.golden @@ -0,0 +1,77 @@ +{ + "SchemaVersion": 2, + "ArtifactName": "testdata/fixtures/fs/pubspec", + "ArtifactType": "filesystem", + "Metadata": { + "ImageConfig": { + "architecture": "", + "created": "0001-01-01T00:00:00Z", + "os": "", + "rootfs": { + "type": "", + "diff_ids": null + }, + "config": {} + } + }, + "Results": [ + { + "Target": "pubspec.lock", + "Class": "lang-pkgs", + "Type": "pub", + "Packages": [ + { + "ID": "http@0.13.2", + "Name": "http", + "Version": "0.13.2" + }, + { + "ID": "shelf@1.3.1", + "Name": "shelf", + "Version": "1.3.1", + "Indirect": true + } + ], + "Vulnerabilities": [ + { + "VulnerabilityID": "CVE-2020-35669", + "PkgName": "http", + "PkgID": "http@0.13.2", + "InstalledVersion": "0.13.2", + "FixedVersion": "0.13.3", + "Layer": {}, + "SeveritySource": "ghsa", + "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2020-35669", + "DataSource": { + "ID": "ghsa", + "Name": "GitHub Security Advisory Pub", + "URL": "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Apub" + }, + "Title": "http before 0.13.3 vulnerable to header injection", + "Description": "An issue was discovered in the http package before 0.13.3 for Dart. If the attacker controls the HTTP method and the app is using Request directly, it's possible to achieve CRLF injection in an HTTP request via HTTP header injection. This issue has been addressed in commit abb2bb182 by validating request methods.", + "Severity": "MEDIUM", + "CweIDs": [ + "CWE-74" + ], + "CVSS": { + "ghsa": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N", + "V3Score": 6.1 + } + }, + "References": [ + "https://nvd.nist.gov/vuln/detail/CVE-2020-35669", + "https://github.com/dart-lang/http/issues/511", + "https://github.com/dart-lang/http/blob/master/CHANGELOG.md#0133", + "https://github.com/dart-lang/http/pull/512", + "https://github.com/dart-lang/http/commit/abb2bb182fbd7f03aafd1f889b902d7b3bdb8769", + "https://pub.dev/packages/http/changelog#0133", + "https://github.com/advisories/GHSA-4rgh-jx4f-qfcq" + ], + "PublishedDate": "2022-05-24T17:37:16Z", + "LastModifiedDate": "2022-10-06T20:26:08Z" + } + ] + } + ] +} diff --git a/pkg/detector/library/driver.go b/pkg/detector/library/driver.go index 585964136f..92f79a096e 100644 --- a/pkg/detector/library/driver.go +++ b/pkg/detector/library/driver.go @@ -51,6 +51,9 @@ func NewDriver(libType string) (Driver, error) { case ftypes.Pipenv, ftypes.Poetry, ftypes.Pip, ftypes.PythonPkg: ecosystem = vulnerability.Pip comparer = pep440.Comparer{} + case ftypes.Pub: + ecosystem = vulnerability.Pub + comparer = compare.GenericComparer{} case ftypes.Hex: ecosystem = vulnerability.Erlang comparer = compare.GenericComparer{} diff --git a/pkg/fanal/analyzer/all/import.go b/pkg/fanal/analyzer/all/import.go index 9564f907cf..3540767f9c 100644 --- a/pkg/fanal/analyzer/all/import.go +++ b/pkg/fanal/analyzer/all/import.go @@ -6,6 +6,7 @@ import ( _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/all" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/executable" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/c/conan" + _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/dart/pub" _ "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/elixir/mix" diff --git a/pkg/fanal/analyzer/const.go b/pkg/fanal/analyzer/const.go index 46333e231c..e315e7f8fb 100644 --- a/pkg/fanal/analyzer/const.go +++ b/pkg/fanal/analyzer/const.go @@ -80,6 +80,9 @@ const ( // Swift TypeCocoaPods Type = "cocoapods" + // Dart + TypePubSpecLock Type = "pubspec-lock" + // ============ // Non-packaged // ============ @@ -131,14 +134,14 @@ var ( TypeBundler, TypeGemSpec, TypeCargo, TypeComposer, TypeJar, TypePom, TypeGradleLock, TypeNpmPkgLock, TypeNodePkg, TypeYarn, TypePnpm, TypeNuget, TypeDotNetCore, TypePythonPkg, TypePip, TypePipenv, TypePoetry, TypeGoBinary, TypeGoMod, TypeRustBinary, TypeConanLock, - TypeCocoaPods, TypeMixLock, + TypeCocoaPods, TypePubSpecLock, TypeMixLock, } // TypeLockfiles has all lock file analyzers TypeLockfiles = []Type{ TypeBundler, TypeNpmPkgLock, TypeYarn, TypePnpm, TypePip, TypePipenv, TypePoetry, TypeGoMod, TypePom, TypeConanLock, TypeGradleLock, - TypeCocoaPods, TypeMixLock, + TypeCocoaPods, TypePubSpecLock, TypeMixLock, } // TypeIndividualPkgs has all analyzers for individual packages diff --git a/pkg/fanal/analyzer/language/dart/pub/pubspec.go b/pkg/fanal/analyzer/language/dart/pub/pubspec.go new file mode 100644 index 0000000000..5961d9ae2a --- /dev/null +++ b/pkg/fanal/analyzer/language/dart/pub/pubspec.go @@ -0,0 +1,46 @@ +package pub + +import ( + "context" + "os" + "path/filepath" + + "golang.org/x/xerrors" + + "github.com/aquasecurity/go-dep-parser/pkg/dart/pub" + "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(&pubSpecLockAnalyzer{}) +} + +const ( + version = 1 +) + +// pubSpecLockAnalyzer analyzes pubspec.lock +type pubSpecLockAnalyzer struct{} + +func (a pubSpecLockAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput) (*analyzer.AnalysisResult, error) { + p := pub.NewParser() + res, err := language.Analyze(types.Pub, input.FilePath, input.Content, p) + if err != nil { + return nil, xerrors.Errorf("%s parse error: %w", input.FilePath, err) + } + return res, nil +} + +func (a pubSpecLockAnalyzer) Required(filePath string, _ os.FileInfo) bool { + return filepath.Base(filePath) == types.PubSpecLock +} + +func (a pubSpecLockAnalyzer) Type() analyzer.Type { + return analyzer.TypePubSpecLock +} + +func (a pubSpecLockAnalyzer) Version() int { + return version +} diff --git a/pkg/fanal/analyzer/language/dart/pub/pubspec_test.go b/pkg/fanal/analyzer/language/dart/pub/pubspec_test.go new file mode 100644 index 0000000000..03599dfd96 --- /dev/null +++ b/pkg/fanal/analyzer/language/dart/pub/pubspec_test.go @@ -0,0 +1,115 @@ +package pub + +import ( + "github.com/aquasecurity/trivy/pkg/fanal/analyzer" + "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "os" + "sort" + "testing" +) + +func Test_pubSpecLockAnalyzer_Analyze(t *testing.T) { + tests := []struct { + name string + inputFile string + want *analyzer.AnalysisResult + wantErr assert.ErrorAssertionFunc + }{ + { + name: "happy path", + inputFile: "testdata/happy.lock", + want: &analyzer.AnalysisResult{ + Applications: []types.Application{ + { + Type: types.Pub, + FilePath: "testdata/happy.lock", + Libraries: []types.Package{ + { + ID: "crypto@3.0.2", + Name: "crypto", + Version: "3.0.2", + }, + { + ID: "flutter_test@0.0.0", + Name: "flutter_test", + Version: "0.0.0", + }, + { + ID: "uuid@3.0.6", + Name: "uuid", + Version: "3.0.6", + Indirect: true, + }, + }, + }, + }, + }, + wantErr: assert.NoError, + }, + { + name: "empty file", + inputFile: "testdata/empty.lock", + wantErr: assert.NoError, + }, + { + name: "broken file", + inputFile: "testdata/broken.lock", + wantErr: assert.Error, + }, + } + + 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 := pubSpecLockAnalyzer{} + 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 + }) + } + } + + if !tt.wantErr(t, err, tt.inputFile) { + return + } + assert.Equal(t, tt.want, got) + }) + } +} + +func Test_pubSpecLockAnalyzer_Required(t *testing.T) { + tests := []struct { + name string + filePath string + want bool + }{ + { + name: "happy path", + filePath: "pubspec.lock", + want: true, + }, + { + name: "sad path", + filePath: "test.txt", + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := pubSpecLockAnalyzer{} + got := a.Required(tt.filePath, nil) + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/pkg/fanal/analyzer/language/dart/pub/testdata/broken.lock b/pkg/fanal/analyzer/language/dart/pub/testdata/broken.lock new file mode 100644 index 0000000000..66c0ff41b8 --- /dev/null +++ b/pkg/fanal/analyzer/language/dart/pub/testdata/broken.lock @@ -0,0 +1 @@ +it is broken \ No newline at end of file diff --git a/pkg/fanal/analyzer/language/dart/pub/testdata/empty.lock b/pkg/fanal/analyzer/language/dart/pub/testdata/empty.lock new file mode 100644 index 0000000000..eb4cea8c20 --- /dev/null +++ b/pkg/fanal/analyzer/language/dart/pub/testdata/empty.lock @@ -0,0 +1,6 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: +sdks: + dart: ">=2.18.0 <3.0.0" + flutter: ">=3.3.0" \ No newline at end of file diff --git a/pkg/fanal/analyzer/language/dart/pub/testdata/happy.lock b/pkg/fanal/analyzer/language/dart/pub/testdata/happy.lock new file mode 100644 index 0000000000..3a37840aa3 --- /dev/null +++ b/pkg/fanal/analyzer/language/dart/pub/testdata/happy.lock @@ -0,0 +1,25 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + crypto: + dependency: "direct main" + description: + name: crypto + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.2" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + uuid: + dependency: transitive + description: + name: uuid + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.6" +sdks: + dart: ">=2.18.0 <3.0.0" + flutter: ">=3.3.0" \ No newline at end of file diff --git a/pkg/fanal/types/const.go b/pkg/fanal/types/const.go index 94f4de2c0b..afadf3d8da 100644 --- a/pkg/fanal/types/const.go +++ b/pkg/fanal/types/const.go @@ -30,6 +30,7 @@ const ( RustBinary = "rustbinary" Conan = "conan" Cocoapods = "cocoapods" + Pub = "pub" Hex = "hex" // Config files @@ -75,5 +76,7 @@ const ( CocoaPodsLock = "Podfile.lock" + PubSpecLock = "pubspec.lock" + MixLock = "mix.lock" ) diff --git a/pkg/purl/purl.go b/pkg/purl/purl.go index 388183162e..ee8e5484c1 100644 --- a/pkg/purl/purl.go +++ b/pkg/purl/purl.go @@ -16,8 +16,9 @@ import ( ) const ( - TypeAPK = "apk" // not defined in github.com/package-url/packageurl-go - TypeOCI = "oci" + TypeAPK = "apk" // not defined in github.com/package-url/packageurl-go + TypeOCI = "oci" + TypeDart = "dart" ) type PackageURL struct { @@ -98,6 +99,8 @@ func (p *PackageURL) PackageType() string { return ftypes.Cocoapods case packageurl.TypeHex: return ftypes.Hex + case TypeDart: // TODO: replace with packageurl.TypeDart once they add it. + return ftypes.Pub } return p.Type } @@ -312,6 +315,8 @@ func purlType(t string) string { return packageurl.TypeSwift case ftypes.Hex: return packageurl.TypeHex + case ftypes.Pub: + return TypeDart // TODO: replace with packageurl.TypeDart once they add it. case os.Alpine: return TypeAPK case os.Debian, os.Ubuntu: diff --git a/pkg/purl/purl_test.go b/pkg/purl/purl_test.go index b21d732b9f..297b74f3ef 100644 --- a/pkg/purl/purl_test.go +++ b/pkg/purl/purl_test.go @@ -183,6 +183,21 @@ func TestNewPackageURL(t *testing.T) { }, }, }, + { + name: "dart package", + typ: ftypes.Pub, + pkg: ftypes.Package{ + Name: "http", + Version: "0.13.2", + }, + want: purl.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: purl.TypeDart, + Name: "http", + Version: "0.13.2", + }, + }, + }, { name: "os package", typ: os.RedHat, @@ -393,6 +408,18 @@ func TestFromString(t *testing.T) { }, }, }, + { + name: "happy path for dart", + purl: "pkg:dart/http@0.13.2", + want: purl.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: purl.TypeDart, + Name: "http", + Version: "0.13.2", + Qualifiers: packageurl.Qualifiers{}, + }, + }, + }, { name: "happy path for apk", purl: "pkg:apk/alpine/alpine-baselayout@3.2.0-r16?distro=3.14.2",