├── .github ├── dependabot.yml └── workflows │ └── test.yml ├── .gitignore ├── LICENSE ├── README.md ├── go.mod ├── go.sum └── pkg ├── c └── conan │ ├── parse.go │ ├── parse_test.go │ └── testdata │ ├── empty.lock │ ├── happy.lock │ ├── happy2.lock │ └── sad.lock ├── conda └── meta │ ├── parse.go │ ├── parse_test.go │ └── testdata │ ├── README.md │ ├── _libgcc_mutex-0.1-main.json │ ├── invalid_json.json │ ├── invalid_package.json │ └── libgomp-11.2.0-h1234567_1.json ├── dart └── pub │ ├── parse.go │ ├── parse_test.go │ └── testdata │ ├── broken.lock │ ├── empty.lock │ └── happy.lock ├── dotnet └── core_deps │ ├── parse.go │ ├── parse_test.go │ └── testdata │ ├── ExampleApp1.deps.json │ ├── InvalidJson.deps.json │ └── NoLibraries.deps.json ├── frameworks └── wordpress │ ├── parse.go │ ├── parse_test.go │ └── testdata │ ├── version.php │ └── versionFail.php ├── golang ├── binary │ ├── parse.go │ ├── parse_test.go │ └── testdata │ │ ├── dummy │ │ ├── replace.elf │ │ ├── test.elf │ │ ├── test.exe │ │ └── test.macho ├── mod │ ├── parse.go │ ├── parse_test.go │ ├── parse_testcase.go │ └── testdata │ │ ├── go116 │ │ ├── go.mod │ │ ├── go.sum │ │ └── main.go │ │ ├── no-go-version │ │ ├── go.mod │ │ └── main.go │ │ ├── normal │ │ ├── go.mod │ │ ├── go.sum │ │ └── main.go │ │ ├── replaced-with-local-path-and-version-mismatch │ │ ├── go.mod │ │ ├── go.sum │ │ ├── main.go │ │ └── xerrors │ │ │ ├── go.mod │ │ │ └── xerrors.go │ │ ├── replaced-with-local-path-and-version │ │ ├── go.mod │ │ ├── go.sum │ │ ├── main.go │ │ └── xerrors │ │ │ ├── go.mod │ │ │ └── xerrors.go │ │ ├── replaced-with-local-path │ │ ├── go.mod │ │ ├── go.sum │ │ ├── main.go │ │ └── xerrors │ │ │ ├── go.mod │ │ │ └── xerrors.go │ │ ├── replaced-with-version-mismatch │ │ ├── go.mod │ │ ├── go.sum │ │ └── main.go │ │ ├── replaced-with-version │ │ ├── go.mod │ │ ├── go.sum │ │ └── main.go │ │ └── replaced │ │ ├── go.mod │ │ ├── go.sum │ │ └── main.go └── sum │ ├── parse.go │ ├── parse_test.go │ ├── parse_testcase.go │ └── testdata │ ├── gomod_emptyline.sum │ ├── gomod_many.sum │ ├── gomod_normal.sum │ └── gomod_trivy.sum ├── gradle └── lockfile │ ├── parse.go │ ├── parse_test.go │ └── testdata │ ├── empty.lockfile │ └── happy.lockfile ├── hex └── mix │ ├── parse.go │ ├── parse_test.go │ └── testdata │ ├── empty.mix.lock │ └── happy.mix.lock ├── io └── io.go ├── java ├── jar │ ├── parse.go │ ├── parse_test.go │ ├── sonatype │ │ ├── log.go │ │ └── sonatype.go │ ├── testdata │ │ ├── gradle.war │ │ ├── hadoop-shaded-guava-1.1.0-SNAPSHOT.jar │ │ ├── heuristic-1.0.0-SNAPSHOT.jar │ │ ├── io.quarkus.gizmo.gizmo-1.1.1.Final.jar │ │ ├── maven.war │ │ ├── nested.jar │ │ ├── test.jar │ │ └── testimage │ │ │ ├── gradle │ │ │ ├── Dockerfile │ │ │ └── build.gradle │ │ │ └── maven │ │ │ ├── Dockerfile │ │ │ └── pom.xml │ └── types.go └── pom │ ├── artifact.go │ ├── artifact_test.go │ ├── cache.go │ ├── parse.go │ ├── parse_test.go │ ├── pom.go │ ├── queue.go │ ├── settings.go │ ├── testdata │ ├── conf │ │ └── settings.xml │ ├── exclusions-in-child │ │ └── pom.xml │ ├── exclusions │ │ └── pom.xml │ ├── happy │ │ └── pom.xml │ ├── hard-requirement │ │ └── pom.xml │ ├── import-dependency-management-multiple │ │ └── pom.xml │ ├── import-dependency-management │ │ └── pom.xml │ ├── inherit-license │ │ ├── module │ │ │ ├── pom.xml │ │ │ └── submodule │ │ │ │ └── pom.xml │ │ └── pom.xml │ ├── inherit-props │ │ ├── base │ │ │ └── pom.xml │ │ └── pom.xml │ ├── multi-module-soft-requirement │ │ ├── module1 │ │ │ └── pom.xml │ │ ├── module2 │ │ │ └── pom.xml │ │ └── pom.xml │ ├── multi-module │ │ ├── module │ │ │ └── pom.xml │ │ └── pom.xml │ ├── multiply-licenses │ │ └── pom.xml │ ├── no-parent-infinity-loop │ │ ├── parent │ │ │ └── pom.xml │ │ └── pom.xml │ ├── not-found-dependency │ │ └── pom.xml │ ├── not-found-module │ │ └── pom.xml │ ├── not-found-parent │ │ └── pom.xml │ ├── offline │ │ └── pom.xml │ ├── parent-child-properties │ │ ├── child │ │ │ └── pom.xml │ │ ├── parent │ │ │ └── pom.xml │ │ └── top-parent │ │ │ └── pom.xml │ ├── parent-dependencies │ │ ├── child │ │ │ └── pom.xml │ │ └── pom.xml │ ├── parent-dependency-management │ │ ├── child │ │ │ └── pom.xml │ │ └── pom.xml │ ├── parent-properties │ │ ├── child │ │ │ └── pom.xml │ │ └── pom.xml │ ├── parent-relative-path │ │ ├── parent │ │ │ └── pom.xml │ │ └── pom.xml │ ├── parent-remote-repository │ │ └── pom.xml │ ├── parent-version-is-property │ │ ├── child │ │ │ └── pom.xml │ │ └── pom.xml │ ├── project-version-from-parent │ │ ├── child │ │ │ └── pom.xml │ │ ├── parent │ │ │ └── pom.xml │ │ └── top-parent │ │ │ └── pom.xml │ ├── repository │ │ └── org │ │ │ └── example │ │ │ ├── example-api │ │ │ ├── 1.7.30 │ │ │ │ └── example-api-1.7.30.pom │ │ │ └── 2.0.0 │ │ │ │ └── example-api-2.0.0.pom │ │ │ ├── example-bom │ │ │ ├── 1.0.0 │ │ │ │ └── example-bom-1.0.0.pom │ │ │ ├── 2.0.0 │ │ │ │ └── example-bom-2.0.0.pom │ │ │ ├── 3.0.0 │ │ │ │ └── example-bom-3.0.0.pom │ │ │ └── 4.0.0 │ │ │ │ └── example-bom-4.0.0.pom │ │ │ ├── example-child-parent │ │ │ └── 2.0.0 │ │ │ │ └── example-child-parent-2.0.0.pom │ │ │ ├── example-child │ │ │ └── 2.0.0 │ │ │ │ └── example-child-2.0.0.pom │ │ │ ├── example-dependency-management │ │ │ ├── 2.2.2 │ │ │ │ └── example-dependency-management-2.2.2.pom │ │ │ └── 3.3.3 │ │ │ │ └── example-dependency-management-3.3.3.pom │ │ │ ├── example-dependency-management2 │ │ │ └── 1.1.1 │ │ │ │ └── example-dependency-management2-1.1.1.pom │ │ │ ├── example-dependency-management3 │ │ │ └── 1.1.1 │ │ │ │ └── example-dependency-management3-1.1.1.pom │ │ │ ├── example-dependency │ │ │ ├── 1.2.3 │ │ │ │ └── example-dependency-1.2.3.pom │ │ │ └── 1.2.4 │ │ │ │ └── example-dependency-1.2.4.pom │ │ │ ├── example-dependency2 │ │ │ └── 2.3.4 │ │ │ │ └── example-dependency2-2.3.4.pom │ │ │ ├── example-exclusions │ │ │ └── 4.0.0 │ │ │ │ └── example-exclusions-4.0.0.pom │ │ │ ├── example-nested │ │ │ ├── 3.3.3 │ │ │ │ └── example-nested-3.3.3.pom │ │ │ └── 3.3.4 │ │ │ │ └── example-nested-3.3.4.pom │ │ │ └── example-parent │ │ │ └── 1.0.0 │ │ │ └── example-parent-1.0.0.pom │ ├── root-pom-dep-management │ │ └── pom.xml │ ├── soft-requirement-with-transitive-dependencies │ │ └── pom.xml │ ├── soft-requirement │ │ └── pom.xml │ ├── transitive-dependency-management │ │ └── pom.xml │ ├── transitive-parents │ │ ├── base │ │ │ └── pom.xml │ │ └── pom.xml │ ├── version-requirement │ │ └── pom.xml │ └── wildcard-exclusions │ │ └── pom.xml │ └── utils.go ├── julia └── manifest │ ├── naive_pkg_parser.go │ ├── parse.go │ ├── parse_test.go │ ├── parse_testcase.go │ └── testdata │ ├── dep_ext_v1.9 │ └── Manifest.toml │ ├── no_deps_v1.6 │ └── Manifest.toml │ ├── no_deps_v1.9 │ └── Manifest.toml │ ├── primary │ ├── Manifest_v1.6.toml │ └── Manifest_v1.8.toml │ └── shadowed_dep_v1.9 │ └── Manifest.toml ├── log └── log.go ├── nodejs ├── npm │ ├── parse.go │ ├── parse_test.go │ ├── parse_testcase.go │ └── testdata │ │ ├── package-lock_v1.json │ │ ├── package-lock_v2.json │ │ ├── package-lock_v3.json │ │ ├── package-lock_v3_with_workspace.json │ │ └── package-lock_v3_without_root_deps_field.json ├── packagejson │ ├── parse.go │ ├── parse_test.go │ └── testdata │ │ ├── invalid_package.json │ │ ├── legacy_package.json │ │ ├── package.json │ │ ├── without_name_and_version_package.json │ │ └── without_version_package.json ├── pnpm │ ├── parse.go │ ├── parse_test.go │ ├── parse_testcase.go │ └── testdata │ │ ├── pnpm-lock_archives.yaml │ │ ├── pnpm-lock_many.yaml │ │ ├── pnpm-lock_normal.yaml │ │ ├── pnpm-lock_v6.yaml │ │ ├── pnpm-lock_v6_with_dev.yaml │ │ └── pnpm-lock_with_dev.yaml └── yarn │ ├── parse.go │ ├── parse_test.go │ ├── parse_testcase.go │ ├── testcase_deps_generator │ ├── Dockerfile │ ├── index.js │ ├── package.json │ └── yarn.lock │ └── testdata │ ├── yarn_many.lock │ ├── yarn_normal.lock │ ├── yarn_react.lock │ ├── yarn_realworld.lock │ ├── yarn_v2_deps_with_protocol.lock │ ├── yarn_v2_many.lock │ ├── yarn_v2_normal.lock │ ├── yarn_v2_react.lock │ ├── yarn_v2_with_dev.lock │ ├── yarn_with_bad_protocol.lock │ ├── yarn_with_dev.lock │ ├── yarn_with_git.lock │ ├── yarn_with_local.lock │ └── yarn_with_npm.lock ├── nuget ├── config │ ├── parse.go │ ├── parse_test.go │ └── testdata │ │ ├── dev_dependency.config │ │ ├── malformed_xml.config │ │ └── packages.config ├── lock │ ├── parse.go │ ├── parse_test.go │ ├── parse_testcase.go │ └── testdata │ │ ├── packages_lock_legacy.json │ │ ├── packages_lock_multi.json │ │ ├── packages_lock_simple.json │ │ └── packages_lock_subdependencies.json └── packagesprops │ ├── parse.go │ ├── parse_test.go │ └── testdata │ ├── Directory.Packages.props │ ├── no_item_group.props │ ├── no_project.props │ ├── packages.props │ ├── several_item_groups │ └── variables_and_empty ├── php └── composer │ ├── parse.go │ ├── parse_test.go │ └── testdata │ └── composer_happy.lock ├── python ├── packaging │ ├── parse.go │ ├── parse_test.go │ └── testdata │ │ ├── distlib-0.3.1-py3.9.egg-info │ │ ├── distlib-0.3.1.METADATA │ │ ├── iniconfig-2.0.0.METADATA │ │ ├── invalid.json │ │ ├── networkx-3.0.METADATA │ │ ├── setuptools-51.3.3-py3.8.egg-info.PKG-INFO │ │ ├── simple-0.1.0.METADATA │ │ ├── unidecode-egg-info.PKG-INFO │ │ └── zipp-3.12.1.METADATA ├── pip │ ├── parse.go │ ├── parse_test.go │ ├── parse_testcase.go │ └── testdata │ │ ├── requirement_exstras.txt │ │ ├── requirements_comments.txt │ │ ├── requirements_flask.txt │ │ ├── requirements_hash.txt │ │ ├── requirements_hyphens.txt │ │ ├── requirements_no_version.txt │ │ ├── requirements_operator.txt │ │ ├── requirements_spaces.txt │ │ └── requirements_utf16le.txt ├── pipenv │ ├── parse.go │ ├── parse_test.go │ ├── parse_testcase.go │ └── testdata │ │ ├── Pipfile_django.lock │ │ ├── Pipfile_many.lock │ │ └── Pipfile_normal.lock ├── poetry │ ├── parse.go │ ├── parse_test.go │ ├── parse_testcase.go │ └── testdata │ │ ├── poetry_flask.lock │ │ ├── poetry_many.lock │ │ └── poetry_normal.lock └── pyproject │ ├── pyproject.go │ ├── pyproject_test.go │ └── testdata │ ├── happy.toml │ └── sad.toml ├── ruby ├── bundler │ ├── parse.go │ ├── parse_test.go │ └── testdata │ │ ├── Gemfile_bundler2.lock │ │ ├── Gemfile_malformed.lock │ │ └── Gemfile_normal.lock └── gemspec │ ├── parse.go │ ├── parse_test.go │ └── testdata │ ├── license.gemspec │ ├── malformed00.gemspec │ ├── malformed01.gemspec │ ├── multiple_licenses.gemspec │ ├── normal00.gemspec │ └── normal01.gemspec ├── rust ├── binary │ ├── parse.go │ ├── parse_test.go │ └── testdata │ │ ├── dummy │ │ ├── test.elf │ │ ├── test.exe │ │ └── test.macho └── cargo │ ├── naive_pkg_parser.go │ ├── parse.go │ ├── parse_test.go │ └── testdata │ ├── cargo_invalid.lock │ ├── cargo_mixed.lock │ ├── cargo_normal.lock │ └── cargo_v3.lock ├── swift ├── cocoapods │ ├── parse.go │ ├── parse_test.go │ └── testdata │ │ ├── empty.lock │ │ ├── happy.lock │ │ └── sad.lock └── swift │ ├── parse.go │ ├── parse_test.go │ ├── testdata │ ├── empty-Package.resolved │ ├── happy-v1-Package.resolved │ └── happy-v2-Package.resolved │ └── types.go ├── types └── types.go └── utils ├── utils.go └── utils_test.go /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gomod 4 | directory: / 5 | schedule: 6 | interval: weekly 7 | - package-ecosystem: github-actions 8 | directory: / 9 | schedule: 10 | interval: weekly 11 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | jobs: 8 | unittest: 9 | name: Unit Test 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Check out code into the Go module directory 13 | uses: actions/checkout@v4 14 | 15 | - name: Set up Go 16 | uses: actions/setup-go@v5 17 | with: 18 | go-version-file: go.mod 19 | 20 | - name: Run unit tests 21 | run: go test ./... 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # GoLand 15 | .idea 16 | 17 | /vendor 18 | 19 | **/.DS_Store 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Teppei Fukuda 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-dep-parser 2 | Dependency Parser for Multiple Programming Languages 3 | 4 | > [!NOTE] 5 | > Moved to [the dependency package](https://github.com/aquasecurity/trivy/tree/main/pkg/dependency) in Trivy 6 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/aquasecurity/go-dep-parser 2 | 3 | go 1.21 4 | 5 | require ( 6 | github.com/BurntSushi/toml v1.3.2 7 | github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 8 | github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492 9 | github.com/hashicorp/go-multierror v1.1.1 10 | github.com/hashicorp/go-retryablehttp v0.7.5 11 | github.com/liamg/jfather v0.0.7 12 | github.com/microsoft/go-rustaudit v0.0.0-20220808201409-204dfee52032 13 | github.com/samber/lo v1.39.0 14 | github.com/stretchr/testify v1.8.4 15 | go.uber.org/zap v1.26.0 16 | golang.org/x/exp v0.0.0-20220407100705-7b9b53b0aca4 17 | golang.org/x/mod v0.15.0 18 | golang.org/x/net v0.20.0 19 | golang.org/x/text v0.14.0 20 | golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 21 | gopkg.in/yaml.v3 v3.0.1 22 | ) 23 | 24 | require ( 25 | github.com/davecgh/go-spew v1.1.1 // indirect 26 | github.com/hashicorp/errwrap v1.0.0 // indirect 27 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 28 | github.com/pmezard/go-difflib v1.0.0 // indirect 29 | go.uber.org/multierr v1.10.0 // indirect 30 | ) 31 | -------------------------------------------------------------------------------- /pkg/c/conan/testdata/empty.lock: -------------------------------------------------------------------------------- 1 | { 2 | "graph_lock": { 3 | "nodes": { 4 | "0": { 5 | "options": "", 6 | "path": "conanfile.txt", 7 | "context": "host" 8 | } 9 | }, 10 | "revisions_enabled": false 11 | }, 12 | "version": "0.4", 13 | "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" 14 | } -------------------------------------------------------------------------------- /pkg/c/conan/testdata/happy.lock: -------------------------------------------------------------------------------- 1 | { 2 | "graph_lock": { 3 | "nodes": { 4 | "0": { 5 | "options": "glew:fPIC=True\nglew:shared=False\nglew:with_egl=False", 6 | "requires": [ 7 | "1", 8 | "3" 9 | ], 10 | "path": "conanfile.txt", 11 | "context": "host" 12 | }, 13 | "1": { 14 | "ref": "pkga/0.0.1", 15 | "options": "fPIC=True\nshared=False\nwith_egl=False", 16 | "package_id": "", 17 | "prev": "0", 18 | "requires": [ 19 | "2" 20 | ], 21 | "context": "host" 22 | }, 23 | "2": { 24 | "ref": "pkgb/system", 25 | "options": "", 26 | "package_id": "", 27 | "prev": "0", 28 | "context": "host" 29 | }, 30 | "3": { 31 | "ref": "pkgc/0.1.1@user/testing", 32 | "options": "shared=False", 33 | "path": "conanfile.txt", 34 | "context": "host" 35 | } 36 | }, 37 | "revisions_enabled": false 38 | }, 39 | "version": "0.4", 40 | "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" 41 | } -------------------------------------------------------------------------------- /pkg/c/conan/testdata/sad.lock: -------------------------------------------------------------------------------- 1 | { 2 | "graph_lock": { 3 | "nodes": { 4 | "0": { 5 | "options": "", 6 | "requires": [ 7 | "1" 8 | ], 9 | "path": "conanfile.txt", 10 | "context": "host" 11 | }, 12 | "1": { 13 | "ref": "wrong/ref/format", 14 | "options": "", 15 | "package_id": "", 16 | "prev": "0", 17 | "context": "host" 18 | } 19 | }, 20 | "revisions_enabled": false 21 | }, 22 | "version": "0.4", 23 | "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" 24 | } -------------------------------------------------------------------------------- /pkg/conda/meta/parse.go: -------------------------------------------------------------------------------- 1 | package meta 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "golang.org/x/xerrors" 7 | 8 | dio "github.com/aquasecurity/go-dep-parser/pkg/io" 9 | "github.com/aquasecurity/go-dep-parser/pkg/types" 10 | ) 11 | 12 | type packageJSON struct { 13 | Name string `json:"name"` 14 | Version string `json:"version"` 15 | License string `json:"license"` 16 | } 17 | 18 | type Parser struct{} 19 | 20 | func NewParser() types.Parser { 21 | return &Parser{} 22 | } 23 | 24 | // Parse parses Anaconda (a.k.a. conda) environment metadata. 25 | // e.g. /envs//conda-meta/.json 26 | // For details see https://conda.io/projects/conda/en/latest/user-guide/concepts/environments.html 27 | func (p *Parser) Parse(r dio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { 28 | var data packageJSON 29 | err := json.NewDecoder(r).Decode(&data) 30 | if err != nil { 31 | return nil, nil, xerrors.Errorf("JSON decode error: %w", err) 32 | } 33 | 34 | if data.Name == "" || data.Version == "" { 35 | return nil, nil, xerrors.Errorf("unable to parse conda package") 36 | } 37 | 38 | return []types.Library{{ 39 | Name: data.Name, 40 | Version: data.Version, 41 | License: data.License, // can be empty 42 | }}, nil, nil 43 | } 44 | -------------------------------------------------------------------------------- /pkg/conda/meta/parse_test.go: -------------------------------------------------------------------------------- 1 | package meta_test 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/stretchr/testify/require" 9 | 10 | "github.com/aquasecurity/go-dep-parser/pkg/conda/meta" 11 | "github.com/aquasecurity/go-dep-parser/pkg/types" 12 | ) 13 | 14 | func TestParse(t *testing.T) { 15 | tests := []struct { 16 | name string 17 | input string 18 | want []types.Library 19 | wantErr string 20 | }{ 21 | { 22 | name: "_libgcc_mutex", 23 | input: "testdata/_libgcc_mutex-0.1-main.json", 24 | want: []types.Library{{Name: "_libgcc_mutex", Version: "0.1"}}, 25 | }, 26 | { 27 | name: "libgomp", 28 | input: "testdata/libgomp-11.2.0-h1234567_1.json", 29 | want: []types.Library{{Name: "libgomp", Version: "11.2.0", License: "GPL-3.0-only WITH GCC-exception-3.1"}}, 30 | }, 31 | { 32 | name: "invalid_json", 33 | input: "testdata/invalid_json.json", 34 | wantErr: "JSON decode error: invalid character", 35 | }, 36 | { 37 | name: "invalid_package", 38 | input: "testdata/invalid_package.json", 39 | wantErr: "unable to parse conda package", 40 | }, 41 | } 42 | for _, tt := range tests { 43 | t.Run(tt.name, func(t *testing.T) { 44 | f, err := os.Open(tt.input) 45 | require.NoError(t, err) 46 | defer f.Close() 47 | 48 | got, _, err := meta.NewParser().Parse(f) 49 | 50 | if tt.wantErr != "" { 51 | assert.ErrorContains(t, err, tt.wantErr) 52 | return 53 | } 54 | 55 | assert.NoError(t, err) 56 | assert.Equal(t, tt.want, got) 57 | }) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /pkg/conda/meta/testdata/README.md: -------------------------------------------------------------------------------- 1 | To recreate the test files: 2 | - Start a miniconda container: 3 | ```bash 4 | docker run --name miniconda --rm -it continuumio/miniconda3@sha256:58b1c7df8d69655ffec017ede784a075e3c2e9feff0fc50ef65300fc75aa45ae bash 5 | ``` 6 | - In the container, initialize a conda environment: 7 | ```bash 8 | conda create --yes -n test-dep-parser python=3.9.12 9 | ``` 10 | - Export conda package definitions out of the container: 11 | ```bash 12 | docker cp miniconda:/opt/conda/envs/test-dep-parser/conda-meta/_libgcc_mutex-0.1-main.json . 13 | docker cp miniconda:/opt/conda/envs/test-dep-parser/conda-meta/libgomp-11.2.0-h1234567_1.json . 14 | ``` 15 | -------------------------------------------------------------------------------- /pkg/conda/meta/testdata/_libgcc_mutex-0.1-main.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": "main", 3 | "build_number": 0, 4 | "channel": "https://repo.anaconda.com/pkgs/main/linux-64", 5 | "constrains": [], 6 | "depends": [], 7 | "extracted_package_dir": "/opt/conda/pkgs/_libgcc_mutex-0.1-main", 8 | "features": "", 9 | "files": [], 10 | "fn": "_libgcc_mutex-0.1-main.conda", 11 | "legacy_bz2_md5": "013d3f22cd3b87f71224bd936765bcad", 12 | "legacy_bz2_size": 3121, 13 | "link": { 14 | "source": "/opt/conda/pkgs/_libgcc_mutex-0.1-main", 15 | "type": 1 16 | }, 17 | "md5": "c3473ff8bdb3d124ed5ff11ec380d6f9", 18 | "name": "_libgcc_mutex", 19 | "package_tarball_full_path": "/opt/conda/pkgs/_libgcc_mutex-0.1-main.conda", 20 | "paths_data": { 21 | "paths": [], 22 | "paths_version": 1 23 | }, 24 | "requested_spec": "None", 25 | "sha256": "476626712f60e5ef0fe04c354727152b1ee5285d57ccd3575c7be930122bd051", 26 | "size": 3473, 27 | "subdir": "linux-64", 28 | "timestamp": 1562011674792, 29 | "track_features": "", 30 | "url": "https://repo.anaconda.com/pkgs/main/linux-64/_libgcc_mutex-0.1-main.conda", 31 | "version": "0.1" 32 | } -------------------------------------------------------------------------------- /pkg/conda/meta/testdata/invalid_json.json: -------------------------------------------------------------------------------- 1 | Invalid JSON -------------------------------------------------------------------------------- /pkg/conda/meta/testdata/invalid_package.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /pkg/dart/pub/parse.go: -------------------------------------------------------------------------------- 1 | package pub 2 | 3 | import ( 4 | "fmt" 5 | "golang.org/x/xerrors" 6 | "gopkg.in/yaml.v3" 7 | 8 | dio "github.com/aquasecurity/go-dep-parser/pkg/io" 9 | "github.com/aquasecurity/go-dep-parser/pkg/types" 10 | ) 11 | 12 | const ( 13 | idFormat = "%s@%s" 14 | transitiveDep = "transitive" 15 | ) 16 | 17 | // Parser is a parser for pubspec.lock 18 | type Parser struct{} 19 | 20 | func NewParser() types.Parser { 21 | return &Parser{} 22 | } 23 | 24 | type lock struct { 25 | Packages map[string]Dep `yaml:"packages"` 26 | } 27 | 28 | type Dep struct { 29 | Dependency string `yaml:"dependency"` 30 | Version string `yaml:"version"` 31 | } 32 | 33 | func (Parser) Parse(r dio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { 34 | l := &lock{} 35 | if err := yaml.NewDecoder(r).Decode(&l); err != nil { 36 | return nil, nil, xerrors.Errorf("failed to decode pubspec.lock: %w", err) 37 | } 38 | var libs []types.Library 39 | for name, dep := range l.Packages { 40 | // We would like to exclude dev dependencies, but we cannot identify 41 | // which indirect dependencies were introduced by dev dependencies 42 | // as there are 3 dependency types, "direct main", "direct dev" and "transitive". 43 | // It will be confusing if we exclude direct dev dependencies and include transitive dev dependencies. 44 | // We decided to keep all dev dependencies until Pub will add support for "transitive main" and "transitive dev". 45 | lib := types.Library{ 46 | ID: pkgID(name, dep.Version), 47 | Name: name, 48 | Version: dep.Version, 49 | Indirect: dep.Dependency == transitiveDep, 50 | } 51 | libs = append(libs, lib) 52 | } 53 | 54 | return libs, nil, nil 55 | } 56 | 57 | func pkgID(name, version string) string { 58 | return fmt.Sprintf(idFormat, name, version) 59 | } 60 | -------------------------------------------------------------------------------- /pkg/dart/pub/parse_test.go: -------------------------------------------------------------------------------- 1 | package pub_test 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "sort" 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | "github.com/stretchr/testify/require" 11 | 12 | "github.com/aquasecurity/go-dep-parser/pkg/dart/pub" 13 | "github.com/aquasecurity/go-dep-parser/pkg/types" 14 | ) 15 | 16 | func TestParser_Parse(t *testing.T) { 17 | tests := []struct { 18 | name string 19 | inputFile string 20 | want []types.Library 21 | wantErr assert.ErrorAssertionFunc 22 | }{ 23 | { 24 | name: "happy path", 25 | inputFile: "testdata/happy.lock", 26 | want: []types.Library{ 27 | { 28 | ID: "crypto@3.0.2", 29 | Name: "crypto", 30 | Version: "3.0.2", 31 | }, 32 | { 33 | ID: "flutter_test@0.0.0", 34 | Name: "flutter_test", 35 | Version: "0.0.0", 36 | }, 37 | { 38 | ID: "uuid@3.0.6", 39 | Name: "uuid", 40 | Version: "3.0.6", 41 | Indirect: true, 42 | }, 43 | }, 44 | wantErr: assert.NoError, 45 | }, 46 | { 47 | name: "empty path", 48 | inputFile: "testdata/empty.lock", 49 | wantErr: assert.NoError, 50 | }, 51 | { 52 | name: "broken yaml", 53 | inputFile: "testdata/broken.lock", 54 | wantErr: assert.Error, 55 | }, 56 | } 57 | 58 | for _, tt := range tests { 59 | t.Run(tt.name, func(t *testing.T) { 60 | f, err := os.Open(tt.inputFile) 61 | require.NoError(t, err) 62 | defer f.Close() 63 | 64 | gotLibs, _, err := pub.NewParser().Parse(f) 65 | if !tt.wantErr(t, err, fmt.Sprintf("Parse(%v)", tt.inputFile)) { 66 | return 67 | } 68 | 69 | sort.Slice(gotLibs, func(i, j int) bool { 70 | return gotLibs[i].ID < gotLibs[j].ID 71 | }) 72 | 73 | assert.Equal(t, tt.want, gotLibs) 74 | }) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /pkg/dart/pub/testdata/broken.lock: -------------------------------------------------------------------------------- 1 | [this is not yaml] -------------------------------------------------------------------------------- /pkg/dart/pub/testdata/empty.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | sdks: 5 | dart: ">=2.18.0 <3.0.0" 6 | flutter: ">=3.3.0" -------------------------------------------------------------------------------- /pkg/dart/pub/testdata/happy.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | crypto: 5 | dependency: "direct main" 6 | description: 7 | name: crypto 8 | url: "https://pub.flutter-io.cn" 9 | source: hosted 10 | version: "3.0.2" 11 | flutter_test: 12 | dependency: "direct dev" 13 | description: flutter 14 | source: sdk 15 | version: "0.0.0" 16 | uuid: 17 | dependency: transitive 18 | description: 19 | name: uuid 20 | url: "https://pub.flutter-io.cn" 21 | source: hosted 22 | version: "3.0.6" 23 | sdks: 24 | dart: ">=2.18.0 <3.0.0" 25 | flutter: ">=3.3.0" -------------------------------------------------------------------------------- /pkg/dotnet/core_deps/parse.go: -------------------------------------------------------------------------------- 1 | package core_deps 2 | 3 | import ( 4 | "github.com/liamg/jfather" 5 | "io" 6 | "strings" 7 | 8 | "golang.org/x/xerrors" 9 | 10 | dio "github.com/aquasecurity/go-dep-parser/pkg/io" 11 | "github.com/aquasecurity/go-dep-parser/pkg/types" 12 | 13 | "github.com/aquasecurity/go-dep-parser/pkg/log" 14 | ) 15 | 16 | type Parser struct{} 17 | 18 | func NewParser() types.Parser { 19 | return &Parser{} 20 | } 21 | 22 | func (p *Parser) Parse(r dio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { 23 | var depsFile dotNetDependencies 24 | 25 | input, err := io.ReadAll(r) 26 | if err != nil { 27 | return nil, nil, xerrors.Errorf("read error: %w", err) 28 | } 29 | if err := jfather.Unmarshal(input, &depsFile); err != nil { 30 | return nil, nil, xerrors.Errorf("failed to decode .deps.json file: %w", err) 31 | } 32 | 33 | var libraries []types.Library 34 | for nameVer, lib := range depsFile.Libraries { 35 | if !strings.EqualFold(lib.Type, "package") { 36 | continue 37 | } 38 | 39 | split := strings.Split(nameVer, "/") 40 | if len(split) != 2 { 41 | // Invalid name 42 | log.Logger.Warnf("Cannot parse .NET library version from: %s", nameVer) 43 | continue 44 | } 45 | 46 | libraries = append(libraries, types.Library{ 47 | Name: split[0], 48 | Version: split[1], 49 | Locations: []types.Location{{StartLine: lib.StartLine, EndLine: lib.EndLine}}, 50 | }) 51 | } 52 | 53 | return libraries, nil, nil 54 | } 55 | 56 | type dotNetDependencies struct { 57 | Libraries map[string]dotNetLibrary `json:"libraries"` 58 | } 59 | 60 | type dotNetLibrary struct { 61 | Type string `json:"type"` 62 | StartLine int 63 | EndLine int 64 | } 65 | 66 | // UnmarshalJSONWithMetadata needed to detect start and end lines of deps 67 | func (t *dotNetLibrary) UnmarshalJSONWithMetadata(node jfather.Node) error { 68 | if err := node.Decode(&t); err != nil { 69 | return err 70 | } 71 | // Decode func will overwrite line numbers if we save them first 72 | t.StartLine = node.Range().Start.Line 73 | t.EndLine = node.Range().End.Line 74 | return nil 75 | } 76 | -------------------------------------------------------------------------------- /pkg/dotnet/core_deps/parse_test.go: -------------------------------------------------------------------------------- 1 | package core_deps 2 | 3 | import ( 4 | "os" 5 | "path" 6 | "sort" 7 | "strings" 8 | "testing" 9 | 10 | "github.com/stretchr/testify/assert" 11 | "github.com/stretchr/testify/require" 12 | 13 | "github.com/aquasecurity/go-dep-parser/pkg/types" 14 | ) 15 | 16 | func TestParse(t *testing.T) { 17 | vectors := []struct { 18 | file string // Test input file 19 | want []types.Library 20 | wantErr string 21 | }{ 22 | { 23 | file: "testdata/ExampleApp1.deps.json", 24 | want: []types.Library{ 25 | {Name: "Newtonsoft.Json", Version: "13.0.1", Locations: []types.Location{{StartLine: 33, EndLine: 39}}}, 26 | }, 27 | }, 28 | { 29 | file: "testdata/NoLibraries.deps.json", 30 | want: nil, 31 | }, 32 | { 33 | file: "testdata/InvalidJson.deps.json", 34 | wantErr: "failed to decode .deps.json file: EOF", 35 | }, 36 | } 37 | 38 | for _, tt := range vectors { 39 | t.Run(path.Base(tt.file), func(t *testing.T) { 40 | f, err := os.Open(tt.file) 41 | require.NoError(t, err) 42 | 43 | got, _, err := NewParser().Parse(f) 44 | if tt.wantErr != "" { 45 | require.NotNil(t, err) 46 | assert.Contains(t, err.Error(), tt.wantErr) 47 | } else { 48 | require.NoError(t, err) 49 | 50 | sort.Slice(got, func(i, j int) bool { 51 | ret := strings.Compare(got[i].Name, got[j].Name) 52 | if ret == 0 { 53 | return got[i].Version < got[j].Version 54 | } 55 | return ret < 0 56 | }) 57 | 58 | sort.Slice(tt.want, func(i, j int) bool { 59 | ret := strings.Compare(tt.want[i].Name, tt.want[j].Name) 60 | if ret == 0 { 61 | return tt.want[i].Version < tt.want[j].Version 62 | } 63 | return ret < 0 64 | }) 65 | 66 | assert.Equal(t, tt.want, got) 67 | } 68 | }) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /pkg/dotnet/core_deps/testdata/ExampleApp1.deps.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtimeTarget": { 3 | "name": ".NETCoreApp,Version=v5.0", 4 | "signature": "" 5 | }, 6 | "compilationOptions": {}, 7 | "targets": { 8 | ".NETCoreApp,Version=v5.0": { 9 | "ExampleApp1/1.0.0": { 10 | "dependencies": { 11 | "Newtonsoft.Json": "13.0.1" 12 | }, 13 | "runtime": { 14 | "ExampleApp1.dll": {} 15 | } 16 | }, 17 | "Newtonsoft.Json/13.0.1": { 18 | "runtime": { 19 | "lib/netstandard2.0/Newtonsoft.Json.dll": { 20 | "assemblyVersion": "13.0.0.0", 21 | "fileVersion": "13.0.1.25517" 22 | } 23 | } 24 | } 25 | } 26 | }, 27 | "libraries": { 28 | "ExampleApp1/1.0.0": { 29 | "type": "project", 30 | "serviceable": false, 31 | "sha512": "" 32 | }, 33 | "Newtonsoft.Json/13.0.1": { 34 | "type": "package", 35 | "serviceable": true, 36 | "sha512": "sha512-ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==", 37 | "path": "newtonsoft.json/13.0.1", 38 | "hashPath": "newtonsoft.json.13.0.1.nupkg.sha512" 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /pkg/dotnet/core_deps/testdata/InvalidJson.deps.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtimeTarget": { 3 | "name": ".NETCoreApp,Version=v5.0", 4 | "signature": "" 5 | }, 6 | "compilationOptions": {}, 7 | "targets": { 8 | ".NETCoreApp,Version=v5.0": { 9 | "ExampleApp1/1.0.0": { 10 | "dependencies": { 11 | "Newtonsoft.Json": "13.0.1" 12 | }, -------------------------------------------------------------------------------- /pkg/dotnet/core_deps/testdata/NoLibraries.deps.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtimeTarget": { 3 | "name": ".NETCoreApp,Version=v5.0", 4 | "signature": "" 5 | }, 6 | "compilationOptions": {}, 7 | "targets": { 8 | ".NETCoreApp,Version=v5.0": { 9 | "ExampleApp1/1.0.0": { 10 | "dependencies": { 11 | "Newtonsoft.Json": "13.0.1" 12 | }, 13 | "runtime": { 14 | "ExampleApp1.dll": {} 15 | } 16 | }, 17 | "Newtonsoft.Json/13.0.1": { 18 | "runtime": { 19 | "lib/netstandard2.0/Newtonsoft.Json.dll": { 20 | "assemblyVersion": "13.0.0.0", 21 | "fileVersion": "13.0.1.25517" 22 | } 23 | } 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /pkg/frameworks/wordpress/parse.go: -------------------------------------------------------------------------------- 1 | package wordpress 2 | 3 | import ( 4 | "bufio" 5 | "io" 6 | "strings" 7 | 8 | "golang.org/x/xerrors" 9 | 10 | "github.com/aquasecurity/go-dep-parser/pkg/types" 11 | ) 12 | 13 | func Parse(r io.Reader) (lib types.Library, err error) { 14 | 15 | // If wordpress file, open file and 16 | // find line with content 17 | // $wp_version = ''; 18 | 19 | var version string 20 | isComment := false 21 | scanner := bufio.NewScanner(r) 22 | for scanner.Scan() { 23 | line := scanner.Text() 24 | 25 | // Remove comment 26 | commentIndex := strings.Index(line, "//") 27 | if commentIndex != -1 { 28 | line = line[:commentIndex] 29 | } 30 | 31 | line = strings.TrimSpace(line) 32 | 33 | // Handle comment 34 | switch { 35 | case strings.HasPrefix(line, "/*"): 36 | isComment = true 37 | continue 38 | case isComment && strings.HasSuffix(line, "*/"): 39 | isComment = false 40 | continue 41 | case isComment: 42 | continue 43 | } 44 | 45 | // It might include $wp_version_something 46 | if !strings.HasPrefix(line, "$wp_version") { 47 | continue 48 | } 49 | 50 | ss := strings.Split(line, "=") 51 | if len(ss) != 2 || strings.TrimSpace(ss[0]) != "$wp_version" { 52 | continue 53 | } 54 | 55 | // Each variable must end with ";". 56 | end := strings.Index(ss[1], ";") 57 | if end == -1 { 58 | continue 59 | } 60 | 61 | // Remove ";" and white space. 62 | version = strings.TrimSpace(ss[1][:end]) 63 | 64 | // Remove single and double quotes. 65 | version = strings.Trim(version, `'"`) 66 | 67 | break 68 | } 69 | 70 | if err = scanner.Err(); err != nil || version == "" { 71 | return types.Library{}, xerrors.New("version.php could not be parsed") 72 | } 73 | 74 | return types.Library{ 75 | Name: "wordpress", 76 | Version: version, 77 | }, nil 78 | } 79 | -------------------------------------------------------------------------------- /pkg/frameworks/wordpress/parse_test.go: -------------------------------------------------------------------------------- 1 | package wordpress 2 | 3 | import ( 4 | "os" 5 | "path" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | "github.com/stretchr/testify/require" 10 | 11 | "github.com/aquasecurity/go-dep-parser/pkg/types" 12 | ) 13 | 14 | func TestParseWordPress(t *testing.T) { 15 | tests := []struct { 16 | file string // Test input file 17 | want types.Library 18 | wantErr string 19 | }{ 20 | { 21 | file: "testdata/version.php", 22 | want: types.Library{ 23 | Name: "wordpress", 24 | Version: "4.9.4-alpha", 25 | }, 26 | }, 27 | { 28 | file: "testdata/versionFail.php", 29 | wantErr: "version.php could not be parsed", 30 | }, 31 | } 32 | 33 | for _, tt := range tests { 34 | t.Run(path.Base(tt.file), func(t *testing.T) { 35 | f, err := os.Open(tt.file) 36 | require.NoError(t, err) 37 | 38 | got, err := Parse(f) 39 | if tt.wantErr != "" { 40 | require.Error(t, err) 41 | assert.Contains(t, err.Error(), tt.wantErr) 42 | return 43 | } 44 | 45 | require.NoError(t, err) 46 | assert.Equal(t, tt.want, got) 47 | }) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /pkg/frameworks/wordpress/testdata/version.php: -------------------------------------------------------------------------------- 1 | ./xerrors 13 | -------------------------------------------------------------------------------- /pkg/golang/mod/testdata/replaced-with-local-path-and-version-mismatch/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/aquasecurity/go-dep-parser/pkg/golang/mod" 7 | ) 8 | 9 | func main() { 10 | if _, err := mod.Parse(nil); err != nil { 11 | log.Fatal(err) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /pkg/golang/mod/testdata/replaced-with-local-path-and-version-mismatch/xerrors/go.mod: -------------------------------------------------------------------------------- 1 | module golang.org/x/xerrors 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /pkg/golang/mod/testdata/replaced-with-local-path-and-version-mismatch/xerrors/xerrors.go: -------------------------------------------------------------------------------- 1 | package xerrors 2 | 3 | func Errorf(format string, a ...interface{}) error { 4 | return nil 5 | } 6 | -------------------------------------------------------------------------------- /pkg/golang/mod/testdata/replaced-with-local-path-and-version/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/org/repo 2 | 3 | go 1.17 4 | 5 | require github.com/aquasecurity/go-dep-parser v0.0.0-20211224170007-df43bca6b6ff 6 | 7 | require ( 8 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 9 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 10 | ) 11 | 12 | replace golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 => ./xerrors 13 | -------------------------------------------------------------------------------- /pkg/golang/mod/testdata/replaced-with-local-path-and-version/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/aquasecurity/go-dep-parser/pkg/golang/mod" 7 | ) 8 | 9 | func main() { 10 | if _, err := mod.Parse(nil); err != nil { 11 | log.Fatal(err) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /pkg/golang/mod/testdata/replaced-with-local-path-and-version/xerrors/go.mod: -------------------------------------------------------------------------------- 1 | module golang.org/x/xerrors 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /pkg/golang/mod/testdata/replaced-with-local-path-and-version/xerrors/xerrors.go: -------------------------------------------------------------------------------- 1 | package xerrors 2 | 3 | func Errorf(format string, a ...interface{}) error { 4 | return nil 5 | } 6 | -------------------------------------------------------------------------------- /pkg/golang/mod/testdata/replaced-with-local-path/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/org/repo 2 | 3 | go 1.17 4 | 5 | require github.com/aquasecurity/go-dep-parser v0.0.0-20211224170007-df43bca6b6ff 6 | 7 | require ( 8 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 9 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 10 | ) 11 | 12 | replace golang.org/x/xerrors => ./xerrors 13 | -------------------------------------------------------------------------------- /pkg/golang/mod/testdata/replaced-with-local-path/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/aquasecurity/go-dep-parser/pkg/golang/mod" 7 | ) 8 | 9 | func main() { 10 | if _, err := mod.Parse(nil); err != nil { 11 | log.Fatal(err) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /pkg/golang/mod/testdata/replaced-with-local-path/xerrors/go.mod: -------------------------------------------------------------------------------- 1 | module golang.org/x/xerrors 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /pkg/golang/mod/testdata/replaced-with-local-path/xerrors/xerrors.go: -------------------------------------------------------------------------------- 1 | package xerrors 2 | 3 | func Errorf(format string, a ...interface{}) error { 4 | return nil 5 | } 6 | -------------------------------------------------------------------------------- /pkg/golang/mod/testdata/replaced-with-version-mismatch/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/org/repo 2 | 3 | go 1.17 4 | 5 | require github.com/aquasecurity/go-dep-parser v0.0.0-20211224170007-df43bca6b6ff 6 | 7 | require ( 8 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 9 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 10 | ) 11 | 12 | replace github.com/aquasecurity/go-dep-parser v0.0.1 => github.com/aquasecurity/go-dep-parser v0.0.0-20220406074731-71021a481237 13 | -------------------------------------------------------------------------------- /pkg/golang/mod/testdata/replaced-with-version-mismatch/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/aquasecurity/go-dep-parser/pkg/golang/mod" 7 | ) 8 | 9 | func main() { 10 | if _, err := mod.Parse(nil); err != nil { 11 | log.Fatal(err) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /pkg/golang/mod/testdata/replaced-with-version/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/org/repo 2 | 3 | go 1.17 4 | 5 | require github.com/aquasecurity/go-dep-parser v0.0.0-20211110174639-8257534ffed3 6 | 7 | require golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 8 | 9 | replace github.com/aquasecurity/go-dep-parser v0.0.0-20211110174639-8257534ffed3 => github.com/aquasecurity/go-dep-parser v0.0.0-20220406074731-71021a481237 10 | -------------------------------------------------------------------------------- /pkg/golang/mod/testdata/replaced-with-version/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/aquasecurity/go-dep-parser/pkg/golang/mod" 7 | ) 8 | 9 | func main() { 10 | if _, err := mod.Parse(nil); err != nil { 11 | log.Fatal(err) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /pkg/golang/mod/testdata/replaced/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/org/repo 2 | 3 | go 1.17 4 | 5 | require github.com/aquasecurity/go-dep-parser v0.0.0-20211110174639-8257534ffed3 6 | 7 | require golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 8 | 9 | replace github.com/aquasecurity/go-dep-parser => github.com/aquasecurity/go-dep-parser v0.0.0-20220406074731-71021a481237 10 | -------------------------------------------------------------------------------- /pkg/golang/mod/testdata/replaced/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/aquasecurity/go-dep-parser/pkg/golang/mod" 7 | ) 8 | 9 | func main() { 10 | if _, err := mod.Parse(nil); err != nil { 11 | log.Fatal(err) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /pkg/golang/sum/parse.go: -------------------------------------------------------------------------------- 1 | package sum 2 | 3 | import ( 4 | "bufio" 5 | "strings" 6 | 7 | "golang.org/x/xerrors" 8 | 9 | "github.com/aquasecurity/go-dep-parser/pkg/golang/mod" 10 | dio "github.com/aquasecurity/go-dep-parser/pkg/io" 11 | "github.com/aquasecurity/go-dep-parser/pkg/types" 12 | ) 13 | 14 | type Parser struct{} 15 | 16 | func NewParser() types.Parser { 17 | return &Parser{} 18 | } 19 | 20 | // Parse parses a go.sum file 21 | func (p *Parser) Parse(r dio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { 22 | var libs []types.Library 23 | uniqueLibs := make(map[string]string) 24 | 25 | scanner := bufio.NewScanner(r) 26 | for scanner.Scan() { 27 | line := strings.TrimSpace(scanner.Text()) 28 | s := strings.Fields(line) 29 | if len(s) < 2 { 30 | continue 31 | } 32 | 33 | // go.sum records and sorts all non-major versions 34 | // with the latest version as last entry 35 | uniqueLibs[s[0]] = strings.TrimSuffix(strings.TrimPrefix(s[1], "v"), "/go.mod") 36 | } 37 | if err := scanner.Err(); err != nil { 38 | return nil, nil, xerrors.Errorf("scan error: %w", err) 39 | } 40 | 41 | for k, v := range uniqueLibs { 42 | libs = append(libs, types.Library{ 43 | ID: mod.ModuleID(k, v), 44 | Name: k, 45 | Version: v, 46 | }) 47 | } 48 | 49 | return libs, nil, nil 50 | } 51 | -------------------------------------------------------------------------------- /pkg/golang/sum/parse_test.go: -------------------------------------------------------------------------------- 1 | package sum 2 | 3 | import ( 4 | "os" 5 | "path" 6 | "sort" 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | "github.com/stretchr/testify/require" 11 | 12 | "github.com/aquasecurity/go-dep-parser/pkg/types" 13 | ) 14 | 15 | func TestParse(t *testing.T) { 16 | vectors := []struct { 17 | file string 18 | want []types.Library 19 | }{ 20 | { 21 | file: "testdata/gomod_normal.sum", 22 | want: GoModNormal, 23 | }, 24 | { 25 | file: "testdata/gomod_emptyline.sum", 26 | want: GoModEmptyLine, 27 | }, 28 | { 29 | file: "testdata/gomod_many.sum", 30 | want: GoModMany, 31 | }, 32 | { 33 | file: "testdata/gomod_trivy.sum", 34 | want: GoModTrivy, 35 | }, 36 | } 37 | 38 | for _, v := range vectors { 39 | t.Run(path.Base(v.file), func(t *testing.T) { 40 | f, err := os.Open(v.file) 41 | require.NoError(t, err) 42 | defer f.Close() 43 | 44 | got, _, err := NewParser().Parse(f) 45 | require.NoError(t, err) 46 | 47 | for i := range got { 48 | got[i].ID = "" // Not compare IDs, tested in mod.TestModuleID() 49 | } 50 | 51 | sort.Slice(got, func(i, j int) bool { 52 | return got[i].Name < got[j].Name 53 | }) 54 | sort.Slice(v.want, func(i, j int) bool { 55 | return v.want[i].Name < v.want[j].Name 56 | }) 57 | 58 | assert.Equal(t, v.want, got) 59 | }) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /pkg/golang/sum/testdata/gomod_emptyline.sum: -------------------------------------------------------------------------------- 1 | github.com/karrick/godirwalk v1.12.0 h1:nkS4xxsjiZMvVlazd0mFyiwD4BR9f3m6LXGhM2TUx3Y= 2 | github.com/karrick/godirwalk v1.12.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= 3 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 4 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 5 | 6 | -------------------------------------------------------------------------------- /pkg/golang/sum/testdata/gomod_normal.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 2 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 3 | -------------------------------------------------------------------------------- /pkg/gradle/lockfile/parse.go: -------------------------------------------------------------------------------- 1 | package lockfile 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "strings" 7 | 8 | dio "github.com/aquasecurity/go-dep-parser/pkg/io" 9 | "github.com/aquasecurity/go-dep-parser/pkg/types" 10 | "github.com/aquasecurity/go-dep-parser/pkg/utils" 11 | ) 12 | 13 | type Parser struct{} 14 | 15 | func NewParser() types.Parser { 16 | return &Parser{} 17 | } 18 | 19 | func (Parser) Parse(r dio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { 20 | var libs []types.Library 21 | scanner := bufio.NewScanner(r) 22 | var lineNum int 23 | for scanner.Scan() { 24 | lineNum++ 25 | line := strings.TrimSpace(scanner.Text()) 26 | if strings.HasPrefix(line, "#") { // skip comments 27 | continue 28 | } 29 | 30 | // dependency format: group:artifact:version=classPaths 31 | dep := strings.Split(line, ":") 32 | if len(dep) != 3 { // skip the last line with lists of empty configurations 33 | continue 34 | } 35 | 36 | name := strings.Join(dep[:2], ":") 37 | version := strings.Split(dep[2], "=")[0] // remove classPaths 38 | libs = append(libs, types.Library{ 39 | ID: fmt.Sprintf("%s:%s", name, version), 40 | Name: name, 41 | Version: version, 42 | Locations: []types.Location{ 43 | { 44 | StartLine: lineNum, 45 | EndLine: lineNum, 46 | }, 47 | }, 48 | }) 49 | 50 | } 51 | return utils.UniqueLibraries(libs), nil, nil 52 | } 53 | -------------------------------------------------------------------------------- /pkg/gradle/lockfile/parse_test.go: -------------------------------------------------------------------------------- 1 | package lockfile 2 | 3 | import ( 4 | "os" 5 | "sort" 6 | "strings" 7 | "testing" 8 | 9 | "github.com/aquasecurity/go-dep-parser/pkg/types" 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func TestParser_Parse(t *testing.T) { 14 | tests := []struct { 15 | name string 16 | inputFile string 17 | want []types.Library 18 | }{ 19 | { 20 | name: "happy path", 21 | inputFile: "testdata/happy.lockfile", 22 | want: []types.Library{ 23 | { 24 | ID: "cglib:cglib-nodep:2.1.2", 25 | Name: "cglib:cglib-nodep", 26 | Version: "2.1.2", 27 | Locations: []types.Location{ 28 | { 29 | StartLine: 4, 30 | EndLine: 4, 31 | }, 32 | }, 33 | }, 34 | { 35 | ID: "org.springframework:spring-asm:3.1.3.RELEASE", 36 | Name: "org.springframework:spring-asm", 37 | Version: "3.1.3.RELEASE", 38 | Locations: []types.Location{ 39 | { 40 | StartLine: 5, 41 | EndLine: 5, 42 | }, 43 | }, 44 | }, 45 | { 46 | ID: "org.springframework:spring-beans:5.0.5.RELEASE", 47 | Name: "org.springframework:spring-beans", 48 | Version: "5.0.5.RELEASE", 49 | Locations: []types.Location{ 50 | { 51 | StartLine: 6, 52 | EndLine: 6, 53 | }, 54 | }, 55 | }, 56 | }, 57 | }, 58 | { 59 | name: "empty", 60 | inputFile: "testdata/empty.lockfile", 61 | want: nil, 62 | }, 63 | } 64 | 65 | for _, tt := range tests { 66 | t.Run(tt.name, func(t *testing.T) { 67 | parser := NewParser() 68 | f, err := os.Open(tt.inputFile) 69 | assert.NoError(t, err) 70 | 71 | libs, _, _ := parser.Parse(f) 72 | sortLibs(libs) 73 | assert.Equal(t, tt.want, libs) 74 | }) 75 | } 76 | } 77 | 78 | func sortLibs(libs []types.Library) { 79 | sort.Slice(libs, func(i, j int) bool { 80 | ret := strings.Compare(libs[i].Name, libs[j].Name) 81 | if ret == 0 { 82 | return libs[i].Version < libs[j].Version 83 | } 84 | return ret < 0 85 | }) 86 | } 87 | -------------------------------------------------------------------------------- /pkg/gradle/lockfile/testdata/empty.lockfile: -------------------------------------------------------------------------------- 1 | # This is a Gradle generated file for dependency locking. 2 | # Manual edits can break the build and are not advised. 3 | # This file is expected to be part of source control. 4 | empty=incomingCatalog -------------------------------------------------------------------------------- /pkg/gradle/lockfile/testdata/happy.lockfile: -------------------------------------------------------------------------------- 1 | # This is a Gradle generated file for dependency locking. 2 | # Manual edits can break the build and are not advised. 3 | # This file is expected to be part of source control. 4 | cglib:cglib-nodep:2.1.2=testRuntimeClasspath,classpath 5 | org.springframework:spring-asm:3.1.3.RELEASE=classpath 6 | org.springframework:spring-beans:5.0.5.RELEASE=compileClasspath, runtimeClasspath 7 | # io.grpc:grpc-api:1.21.1=classpath 8 | empty= -------------------------------------------------------------------------------- /pkg/hex/mix/parse.go: -------------------------------------------------------------------------------- 1 | package mix 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "strings" 7 | "unicode" 8 | 9 | dio "github.com/aquasecurity/go-dep-parser/pkg/io" 10 | "github.com/aquasecurity/go-dep-parser/pkg/log" 11 | "github.com/aquasecurity/go-dep-parser/pkg/types" 12 | "github.com/aquasecurity/go-dep-parser/pkg/utils" 13 | ) 14 | 15 | // Parser is a parser for mix.lock 16 | type Parser struct{} 17 | 18 | func NewParser() types.Parser { 19 | return &Parser{} 20 | } 21 | 22 | func (Parser) Parse(r dio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { 23 | var libs []types.Library 24 | scanner := bufio.NewScanner(r) 25 | var lineNumber int // It is used to save dependency location 26 | for scanner.Scan() { 27 | lineNumber++ 28 | line := strings.TrimSpace(scanner.Text()) 29 | name, body, ok := strings.Cut(line, ":") 30 | if !ok { 31 | // skip 1st and last lines 32 | continue 33 | } 34 | name = strings.Trim(name, `"`) 35 | 36 | // dependency format: 37 | // "": {<:hex|:git>, :, "", "", [:mix], [], hexpm", ""}, 38 | ss := strings.FieldsFunc(body, func(r rune) bool { 39 | return unicode.IsSpace(r) || r == ',' 40 | }) 41 | if len(ss) < 8 { // In the case where array is empty: s == 8, in other cases s > 8 42 | // git repository doesn't have dependency version 43 | // skip these dependencies 44 | if !strings.Contains(ss[0], ":git") { 45 | log.Logger.Warnf("Cannot parse dependency: %s", line) 46 | } else { 47 | log.Logger.Debugf("Skip git dependencies: %s", name) 48 | } 49 | continue 50 | } 51 | version := strings.Trim(ss[2], `"`) 52 | libs = append(libs, types.Library{ 53 | ID: fmt.Sprintf("%s@%s", name, version), 54 | Name: name, 55 | Version: version, 56 | Locations: []types.Location{{StartLine: lineNumber, EndLine: lineNumber}}, 57 | }) 58 | 59 | } 60 | return utils.UniqueLibraries(libs), nil, nil 61 | } 62 | -------------------------------------------------------------------------------- /pkg/hex/mix/parse_test.go: -------------------------------------------------------------------------------- 1 | package mix 2 | 3 | import ( 4 | "os" 5 | "sort" 6 | "strings" 7 | "testing" 8 | 9 | "github.com/aquasecurity/go-dep-parser/pkg/types" 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func TestParser_Parse(t *testing.T) { 14 | tests := []struct { 15 | name string 16 | inputFile string 17 | want []types.Library 18 | }{ 19 | { 20 | name: "happy path", 21 | inputFile: "testdata/happy.mix.lock", 22 | want: []types.Library{ 23 | { 24 | ID: "bunt@0.2.0", 25 | Name: "bunt", 26 | Version: "0.2.0", 27 | Locations: []types.Location{{StartLine: 2, EndLine: 2}}, 28 | }, 29 | { 30 | ID: "credo@1.6.6", 31 | Name: "credo", 32 | Version: "1.6.6", 33 | Locations: []types.Location{{StartLine: 3, EndLine: 3}}, 34 | }, 35 | { 36 | ID: "file_system@0.2.10", 37 | Name: "file_system", 38 | Version: "0.2.10", 39 | Locations: []types.Location{{StartLine: 4, EndLine: 4}}, 40 | }, 41 | { 42 | ID: "jason@1.3.0", 43 | Name: "jason", 44 | Version: "1.3.0", 45 | Locations: []types.Location{{StartLine: 5, EndLine: 5}}, 46 | }, 47 | }, 48 | }, 49 | { 50 | name: "empty", 51 | inputFile: "testdata/empty.mix.lock", 52 | want: nil, 53 | }, 54 | } 55 | 56 | for _, tt := range tests { 57 | t.Run(tt.name, func(t *testing.T) { 58 | parser := NewParser() 59 | f, err := os.Open(tt.inputFile) 60 | assert.NoError(t, err) 61 | 62 | libs, _, _ := parser.Parse(f) 63 | sortLibs(libs) 64 | assert.Equal(t, tt.want, libs) 65 | }) 66 | } 67 | } 68 | 69 | func sortLibs(libs []types.Library) { 70 | sort.Slice(libs, func(i, j int) bool { 71 | ret := strings.Compare(libs[i].Name, libs[j].Name) 72 | if ret == 0 { 73 | return libs[i].Version < libs[j].Version 74 | } 75 | return ret < 0 76 | }) 77 | } 78 | -------------------------------------------------------------------------------- /pkg/hex/mix/testdata/empty.mix.lock: -------------------------------------------------------------------------------- 1 | %{ 2 | } -------------------------------------------------------------------------------- /pkg/hex/mix/testdata/happy.mix.lock: -------------------------------------------------------------------------------- 1 | %{ 2 | "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"}, 3 | "credo": {:hex, :credo, "1.6.6", "f51f8d45db1af3b2e2f7bee3e6d3c871737bda4a91bff00c5eec276517d1a19c", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "625520ce0984ee0f9f1f198165cd46fa73c1e59a17ebc520038b8fce056a5bdc"}, 4 | "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, 5 | "jason": {:hex, :jason, "1.3.0", "fa6b82a934feb176263ad2df0dbd91bf633d4a46ebfdffea0c8ae82953714946", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "53fc1f51255390e0ec7e50f9cb41e751c260d065dcba2bf0d08dc51a4002c2ac"}, 6 | "esaml": {:git, "https://github.com/firezone/esaml.git", "4294a3ac5262582144e117c10a1537287b6c1fe8", []}, 7 | } -------------------------------------------------------------------------------- /pkg/io/io.go: -------------------------------------------------------------------------------- 1 | package io 2 | 3 | import "io" 4 | 5 | type ReadSeekerAt interface { 6 | io.ReadSeeker 7 | io.ReaderAt 8 | } 9 | 10 | type ReadSeekCloserAt interface { 11 | io.ReadSeekCloser 12 | io.ReaderAt 13 | } 14 | 15 | // NopCloser returns a ReadSeekCloserAt with a no-op Close method wrapping 16 | // the provided Reader r. 17 | func NopCloser(r ReadSeekerAt) ReadSeekCloserAt { 18 | return nopCloser{r} 19 | } 20 | 21 | type nopCloser struct { 22 | ReadSeekerAt 23 | } 24 | 25 | func (nopCloser) Close() error { return nil } 26 | -------------------------------------------------------------------------------- /pkg/java/jar/sonatype/log.go: -------------------------------------------------------------------------------- 1 | package sonatype 2 | 3 | import "github.com/aquasecurity/go-dep-parser/pkg/log" 4 | 5 | // logger implements LeveledLogger 6 | // https://github.com/hashicorp/go-retryablehttp/blob/991b9d0a42d13014e3689dd49a94c02be01f4237/client.go#L285-L290 7 | type logger struct{} 8 | 9 | func (logger) Error(msg string, keysAndValues ...interface{}) { 10 | // Use Debugw to suppress errors on failure 11 | if msg == "request failed" { 12 | log.Logger.Debugw(msg, keysAndValues...) 13 | return 14 | } 15 | log.Logger.Errorw(msg, keysAndValues) 16 | } 17 | 18 | func (logger) Info(msg string, keysAndValues ...interface{}) { 19 | log.Logger.Infow(msg, keysAndValues...) 20 | } 21 | 22 | func (logger) Debug(msg string, keysAndValues ...interface{}) { 23 | // This message is displayed too much 24 | if msg == "performing request" { 25 | return 26 | } 27 | log.Logger.Debugw(msg, keysAndValues...) 28 | } 29 | 30 | func (logger) Warn(msg string, keysAndValues ...interface{}) { 31 | log.Logger.Warnw(msg, keysAndValues...) 32 | } 33 | -------------------------------------------------------------------------------- /pkg/java/jar/testdata/gradle.war: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/go-dep-parser/1de9a375c6295ae769042b9cde998be6c0065a5d/pkg/java/jar/testdata/gradle.war -------------------------------------------------------------------------------- /pkg/java/jar/testdata/hadoop-shaded-guava-1.1.0-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/go-dep-parser/1de9a375c6295ae769042b9cde998be6c0065a5d/pkg/java/jar/testdata/hadoop-shaded-guava-1.1.0-SNAPSHOT.jar -------------------------------------------------------------------------------- /pkg/java/jar/testdata/heuristic-1.0.0-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/go-dep-parser/1de9a375c6295ae769042b9cde998be6c0065a5d/pkg/java/jar/testdata/heuristic-1.0.0-SNAPSHOT.jar -------------------------------------------------------------------------------- /pkg/java/jar/testdata/io.quarkus.gizmo.gizmo-1.1.1.Final.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/go-dep-parser/1de9a375c6295ae769042b9cde998be6c0065a5d/pkg/java/jar/testdata/io.quarkus.gizmo.gizmo-1.1.1.Final.jar -------------------------------------------------------------------------------- /pkg/java/jar/testdata/maven.war: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/go-dep-parser/1de9a375c6295ae769042b9cde998be6c0065a5d/pkg/java/jar/testdata/maven.war -------------------------------------------------------------------------------- /pkg/java/jar/testdata/nested.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/go-dep-parser/1de9a375c6295ae769042b9cde998be6c0065a5d/pkg/java/jar/testdata/nested.jar -------------------------------------------------------------------------------- /pkg/java/jar/testdata/test.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/go-dep-parser/1de9a375c6295ae769042b9cde998be6c0065a5d/pkg/java/jar/testdata/test.jar -------------------------------------------------------------------------------- /pkg/java/jar/testdata/testimage/gradle/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gradle:6.8.1-jdk 2 | RUN gradle init --type java-application 3 | COPY build.gradle app/ 4 | RUN gradle war 5 | -------------------------------------------------------------------------------- /pkg/java/jar/testdata/testimage/gradle/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'application' 3 | id 'war' 4 | } 5 | 6 | repositories { 7 | // Use JCenter for resolving dependencies. 8 | jcenter() 9 | } 10 | 11 | dependencies { 12 | // Use JUnit test framework. 13 | testImplementation 'junit:junit:4.13' 14 | 15 | implementation 'commons-dbcp:commons-dbcp:1.4' 16 | implementation 'commons-pool:commons-pool:1.6' 17 | implementation 'log4j:log4j:1.2.17' 18 | implementation 'org.apache.commons:commons-compress:1.19' 19 | } 20 | 21 | application { 22 | // Define the main class for the application. 23 | mainClass = 'gradle.App' 24 | } 25 | 26 | -------------------------------------------------------------------------------- /pkg/java/jar/testdata/testimage/maven/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM maven:3.6.3-jdk-11 2 | 3 | RUN mvn archetype:generate -DgroupId=com.example -DartifactId=web-app -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false 4 | WORKDIR /web-app 5 | COPY pom.xml . 6 | RUN mvn clean install && mvn package 7 | 8 | CMD ["mvn", "dependency:tree"] 9 | -------------------------------------------------------------------------------- /pkg/java/jar/testdata/testimage/maven/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.example 5 | web-app 6 | war 7 | 1.0-SNAPSHOT 8 | web-app Maven Webapp 9 | http://maven.apache.org 10 | 11 | 12 | junit 13 | junit 14 | 3.8.1 15 | test 16 | 17 | 18 | com.fasterxml.jackson.core 19 | jackson-databind 20 | 2.9.10.6 21 | 22 | 23 | com.cronutils 24 | cron-utils 25 | 9.1.2 26 | 27 | 28 | 29 | web-app 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /pkg/java/jar/types.go: -------------------------------------------------------------------------------- 1 | package jar 2 | 3 | import ( 4 | "fmt" 5 | "github.com/aquasecurity/go-dep-parser/pkg/types" 6 | "golang.org/x/xerrors" 7 | ) 8 | 9 | var ArtifactNotFoundErr = xerrors.New("no artifact found") 10 | 11 | type Properties struct { 12 | GroupID string 13 | ArtifactID string 14 | Version string 15 | FilePath string // path to file containing these props 16 | } 17 | 18 | func (p Properties) Library() types.Library { 19 | return types.Library{ 20 | Name: fmt.Sprintf("%s:%s", p.GroupID, p.ArtifactID), 21 | Version: p.Version, 22 | FilePath: p.FilePath, 23 | } 24 | } 25 | 26 | func (p Properties) Valid() bool { 27 | return p.GroupID != "" && p.ArtifactID != "" && p.Version != "" 28 | } 29 | 30 | func (p Properties) String() string { 31 | return fmt.Sprintf("%s:%s:%s", p.GroupID, p.ArtifactID, p.Version) 32 | } 33 | -------------------------------------------------------------------------------- /pkg/java/pom/cache.go: -------------------------------------------------------------------------------- 1 | package pom 2 | 3 | import "fmt" 4 | 5 | type pomCache map[string]*analysisResult 6 | 7 | func newPOMCache() pomCache { 8 | return pomCache{} 9 | } 10 | 11 | func (c pomCache) put(art artifact, result analysisResult) { 12 | c[c.key(art)] = &result 13 | } 14 | 15 | func (c pomCache) get(art artifact) *analysisResult { 16 | return c[c.key(art)] 17 | } 18 | 19 | func (c pomCache) key(art artifact) string { 20 | return fmt.Sprintf("%s:%s", art.Name(), art.Version) 21 | } 22 | -------------------------------------------------------------------------------- /pkg/java/pom/queue.go: -------------------------------------------------------------------------------- 1 | package pom 2 | 3 | import "sync" 4 | 5 | // artifactQueue the queue of Items 6 | type artifactQueue struct { 7 | items []artifact 8 | lock sync.RWMutex 9 | } 10 | 11 | func newArtifactQueue() *artifactQueue { 12 | return &artifactQueue{} 13 | } 14 | 15 | func (s *artifactQueue) enqueue(items ...artifact) { 16 | s.lock.Lock() 17 | s.items = append(s.items, items...) 18 | s.lock.Unlock() 19 | } 20 | 21 | func (s *artifactQueue) dequeue() artifact { 22 | s.lock.Lock() 23 | item := s.items[0] 24 | s.items = s.items[1:] 25 | s.lock.Unlock() 26 | return item 27 | } 28 | 29 | // IsEmpty returns true if the queue is empty 30 | func (s *artifactQueue) IsEmpty() bool { 31 | return len(s.items) == 0 32 | } 33 | -------------------------------------------------------------------------------- /pkg/java/pom/settings.go: -------------------------------------------------------------------------------- 1 | package pom 2 | 3 | import ( 4 | "encoding/xml" 5 | "os" 6 | "path/filepath" 7 | 8 | "golang.org/x/net/html/charset" 9 | ) 10 | 11 | type settings struct { 12 | LocalRepository string `xml:"localRepository"` 13 | } 14 | 15 | func readSettings() settings { 16 | userSettingsPath := filepath.Join(os.Getenv("HOME"), ".m2", "settings.xml") 17 | userSettings, err := openSettings(userSettingsPath) 18 | if err == nil && userSettings.LocalRepository != "" { 19 | return userSettings 20 | } 21 | 22 | globalSettingsPath := filepath.Join(os.Getenv("MAVEN_HOME"), "conf", "settings.xml") 23 | globalSettings, err := openSettings(globalSettingsPath) 24 | if err == nil && globalSettings.LocalRepository != "" { 25 | return globalSettings 26 | } 27 | 28 | return settings{} 29 | } 30 | 31 | func openSettings(filePath string) (settings, error) { 32 | f, err := os.Open(filePath) 33 | if err != nil { 34 | return settings{}, err 35 | } 36 | 37 | s := settings{} 38 | decoder := xml.NewDecoder(f) 39 | decoder.CharsetReader = charset.NewReaderLabel 40 | if err = decoder.Decode(&s); err != nil { 41 | return settings{}, err 42 | } 43 | return s, nil 44 | } 45 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/exclusions-in-child/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | example 7 | 1.0.0 8 | 9 | 10 | 11 | org.example 12 | example-exclusions 13 | 4.0.0 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/exclusions/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | exclusions 7 | 3.0.0 8 | 9 | pom 10 | exclusions 11 | Exclusions 12 | 13 | 14 | 15 | org.example 16 | example-nested 17 | 3.3.3 18 | 19 | 20 | org.example 21 | example-api 22 | 23 | 24 | org.example 25 | example-api-common 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/happy/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | happy 7 | 1.0.0 8 | 9 | happy 10 | Example 11 | 12 | 13 | 14 | BSD-3-Clause 15 | https://opensource.org/licenses/BSD-3-Clause 16 | repo 17 | 18 | 19 | 20 | 21 | 22 | knqyf263 23 | https://github.com/knqyf263 24 | 25 | 26 | 27 | 28 | 1.7.30 29 | 30 | 31 | 32 | 33 | org.example 34 | example-api 35 | ${api.version} 36 | 37 | 38 | org.example 39 | example-provided 40 | 999 41 | provided 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/hard-requirement/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | hard 7 | 1.0.0 8 | 9 | soft 10 | Example 11 | 12 | 13 | 14 | Apache 2.0 15 | http://www.apache.org/licenses/LICENSE-2.0.html 16 | repo 17 | 18 | 19 | 20 | 21 | 22 | knqyf263 23 | https://github.com/knqyf263 24 | 25 | 26 | 27 | 28 | 29 | org.example 30 | example-nested 31 | 3.3.4 32 | 33 | 34 | org.example 35 | example-dependency 36 | 1.2.4 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/import-dependency-management-multiple/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | import 7 | 2.0.0 8 | 9 | pom 10 | import 11 | Import dependencyManagement 12 | 13 | 14 | 15 | Apache 2.0 16 | http://www.apache.org/licenses/LICENSE-2.0.html 17 | repo 18 | 19 | 20 | 21 | 22 | 23 | 24 | org.example 25 | example-dependency-management 26 | 2.2.2 27 | import 28 | pom 29 | 30 | 31 | 32 | org.example 33 | example-dependency-management2 34 | 1.1.1 35 | import 36 | pom 37 | 38 | 39 | 40 | 41 | 42 | 43 | org.example 44 | example-api 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/import-dependency-management/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | import 7 | 2.0.0 8 | 9 | pom 10 | import 11 | Import dependencyManagement 12 | 13 | 14 | 15 | Apache 2.0 16 | http://www.apache.org/licenses/LICENSE-2.0.html 17 | repo 18 | 19 | 20 | 21 | 22 | 23 | 24 | org.example 25 | example-dependency-management 26 | 3.3.3 27 | import 28 | pom 29 | 30 | 31 | 32 | 33 | 34 | 35 | org.example 36 | example-api 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/inherit-license/module/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | com.example.app 5 | my-app 6 | 1.0.0 7 | 8 | pom 9 | module 10 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/inherit-license/module/submodule/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | com.example.app 5 | module 6 | 1.0.0 7 | 8 | 9 | submodule 10 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/inherit-license/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | pom 4 | com.example.app 5 | my-app 6 | 1.0.0 7 | 8 | 9 | 10 | Apache-2.0 11 | https://www.apache.org/licenses/LICENSE-2.0 12 | repo 13 | 14 | 15 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/inherit-props/base/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.example 7 | parent 8 | 1.0.0 9 | 10 | com.example 11 | test 12 | 0.0.1-SNAPSHOT 13 | Spring Boot project 14 | 15 | 2.0.0 16 | 17 | 18 | 19 | org.example 20 | example-api 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/inherit-props/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | parent 7 | 1.0.0 8 | 9 | pom 10 | parent 11 | Parent 12 | 13 | 14 | 1.0.0 15 | 16 | 17 | 18 | 19 | 20 | org.example 21 | example-bom 22 | ${bom.version} 23 | pom 24 | import 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/multi-module-soft-requirement/module1/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | module1 7 | 1.1.1 8 | 9 | module1 10 | Module 1 11 | 12 | 13 | 1.7.30 14 | 15 | 16 | 17 | 18 | org.example 19 | example-api 20 | ${api.version} 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/multi-module-soft-requirement/module2/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | module2 7 | 1.1.1 8 | 9 | module2 10 | Module 2 11 | 12 | 13 | 2.0.0 14 | 15 | 16 | 17 | 18 | org.example 19 | example-api 20 | ${api.version} 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/multi-module-soft-requirement/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | aggregation 7 | 1.0.0 8 | 9 | pom 10 | aggregation 11 | Aggregation 12 | 13 | 14 | module1 15 | module2 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/multi-module/module/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | module 7 | 1.1.1 8 | 9 | module 10 | Module 11 | 12 | 13 | 14 | Apache 2.0 15 | http://www.apache.org/licenses/LICENSE-2.0.html 16 | repo 17 | 18 | 19 | 20 | 21 | 22 | org.example 23 | example-dependency 24 | 1.2.3 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/multi-module/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | aggregation 7 | 1.0.0 8 | 9 | pom 10 | aggregation 11 | Aggregation 12 | 13 | 14 | 15 | Apache 2.0 16 | http://www.apache.org/licenses/LICENSE-2.0.html 17 | repo 18 | 19 | 20 | 21 | 22 | module 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/multiply-licenses/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | multiply-licenses 7 | 1.0.0 8 | 9 | multiply-licenses 10 | Example 11 | 12 | 13 | 14 | MIT 15 | All source code is under the MIT license. 16 | 17 | 18 | Apache 2.0 19 | http://www.apache.org/licenses/LICENSE-2.0.html 20 | repo 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/no-parent-infinity-loop/parent/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | parent 7 | 1.0.0 8 | 9 | pom 10 | parent 11 | Parent 12 | 13 | 14 | org.example 15 | example-api 16 | 1.7.30 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/no-parent-infinity-loop/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | child 6 | 7 | child 8 | Child 9 | 10 | 11 | com.example 12 | parent 13 | 1.0.0 14 | ./parent 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/not-found-dependency/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | not-found-dependency 7 | 1.0.0 8 | 9 | sad 10 | Sad path 11 | 12 | 13 | 14 | Apache 2.0 15 | http://www.apache.org/licenses/LICENSE-2.0.html 16 | repo 17 | 18 | 19 | 20 | 21 | 22 | org.example 23 | example-not-found 24 | 999 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/not-found-module/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | aggregation 7 | 1.0.0 8 | 9 | pom 10 | aggregation 11 | Aggregation 12 | 13 | 14 | 15 | Apache 2.0 16 | http://www.apache.org/licenses/LICENSE-2.0.html 17 | repo 18 | 19 | 20 | 21 | 22 | module 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/not-found-parent/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | no-parent 7 | 1.0-SNAPSHOT 8 | 9 | no-parent 10 | Parent not found 11 | 12 | 13 | com.example 14 | parent 15 | 1.0.0 16 | 17 | 18 | 19 | 20 | Apache 2.0 21 | http://www.apache.org/licenses/LICENSE-2.0.html 22 | repo 23 | 24 | 25 | 26 | 27 | 28 | org.example 29 | example-api 30 | 1.7.30 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/offline/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | child 6 | 7 | child 8 | Child 9 | 10 | 11 | com.example 12 | parent 13 | ${revision}-${changelist} 14 | 15 | 16 | 17 | 18 | org.example 19 | example-offline 20 | 2.3.4 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/parent-child-properties/child/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | child 6 | 7 | child 8 | Child 9 | 10 | 11 | com.example 12 | parent 13 | 1.0.0 14 | ../parent 15 | 16 | 17 | 18 | 4.0.0 19 | 20 | 21 | 22 | 23 | org.example 24 | example-dependency 25 | 1.2.3 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/parent-child-properties/parent/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 6 | com.example 7 | top-parent 8 | 1.0.0 9 | ../top-parent 10 | 11 | 12 | 13 | com.example 14 | parent 15 | 1.0.0 16 | 17 | pom 18 | parent 19 | Parent 20 | 21 | 22 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/parent-child-properties/top-parent/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | top-parent 7 | 1.0.0 8 | 9 | pom 10 | top-parent 11 | Parent 12 | 13 | 14 | 3.0.0 15 | 16 | 17 | 18 | 19 | 20 | org.example 21 | example-bom 22 | ${bom.version} 23 | pom 24 | import 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/parent-dependencies/child/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | child 6 | 7 | child 8 | Child 9 | 10 | 11 | com.example 12 | parent 13 | ${revision}-${changelist} 14 | 15 | 16 | 17 | 18 | Apache 2.0 19 | http://www.apache.org/licenses/LICENSE-2.0.html 20 | repo 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/parent-dependencies/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | parent 7 | ${revision}${changelist} 8 | 9 | pom 10 | parent 11 | Parent 12 | 13 | 14 | 15 | Apache 2.0 16 | http://www.apache.org/licenses/LICENSE-2.0.html 17 | repo 18 | 19 | 20 | 21 | 22 | 1.0.0 23 | -SNAPSHOT 24 | 1.7.30 25 | 26 | 27 | 28 | 29 | org.example 30 | example-api 31 | ${api.version} 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/parent-dependency-management/child/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | child 6 | 3.0.0 7 | 8 | child 9 | Child 10 | 11 | 12 | com.example 13 | parent 14 | 2.0.0 15 | 16 | 17 | 18 | 19 | Apache 2.0 20 | http://www.apache.org/licenses/LICENSE-2.0.html 21 | repo 22 | 23 | 24 | 25 | 26 | 27 | org.example 28 | example-api 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/parent-dependency-management/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | parent 7 | 2.0.0 8 | 9 | pom 10 | parent 11 | Parent 12 | 13 | 14 | 15 | Apache 2.0 16 | http://www.apache.org/licenses/LICENSE-2.0.html 17 | repo 18 | 19 | 20 | 21 | 22 | 1.7.30 23 | 24 | 25 | 26 | 27 | 28 | org.example 29 | example-api 30 | ${api.version} 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/parent-properties/child/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | child 6 | 7 | child 8 | Child 9 | 10 | 11 | com.example 12 | parent 13 | 1.0.0 14 | 15 | 16 | 17 | 18 | Apache 2.0 19 | http://www.apache.org/licenses/LICENSE-2.0.html 20 | repo 21 | 22 | 23 | 24 | 25 | 26 | 27 | repo.jenkins-ci.org 28 | https://repo.jenkins-ci.org/public/ 29 | 30 | 31 | 32 | 33 | 34 | org.example 35 | example-api 36 | ${api.version} 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/parent-properties/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | parent 7 | 1.0.0 8 | 9 | pom 10 | parent 11 | Parent 12 | 13 | 14 | 15 | Apache 2.0 16 | http://www.apache.org/licenses/LICENSE-2.0.html 17 | repo 18 | 19 | 20 | 21 | 22 | 23 | knqyf263 24 | https://github.com/knqyf263 25 | 26 | 27 | 28 | 29 | 30 | 31 | repo.jenkins-ci.org 32 | https://repo.jenkins-ci.org/public/ 33 | 34 | 35 | 36 | 37 | 1.7.30 38 | 39 | 40 | 41 | 42 | org.example 43 | example-api 44 | 2.2.2 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/parent-relative-path/parent/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | parent 7 | 1.0.0 8 | 9 | pom 10 | parent 11 | Parent 12 | 13 | 14 | 15 | Apache 2.0 16 | http://www.apache.org/licenses/LICENSE-2.0.html 17 | repo 18 | 19 | 20 | 21 | 22 | 23 | knqyf263 24 | https://github.com/knqyf263 25 | 26 | 27 | 28 | 29 | 1.7.30 30 | 31 | 32 | 33 | 34 | org.example 35 | example-api 36 | ${api.version} 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/parent-relative-path/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | child 6 | 7 | child 8 | Child 9 | 10 | 11 | com.example 12 | parent 13 | 1.0.0 14 | ./parent 15 | 16 | 17 | 18 | 19 | Apache 2.0 20 | http://www.apache.org/licenses/LICENSE-2.0.html 21 | repo 22 | 23 | 24 | 25 | 26 | 27 | org.example 28 | example-api 29 | ${api.version} 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/parent-remote-repository/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | child 6 | 7 | child 8 | Child 9 | 10 | 11 | org.example 12 | example-parent 13 | 1.0.0 14 | 15 | 16 | 17 | 18 | Apache 2.0 19 | http://www.apache.org/licenses/LICENSE-2.0.html 20 | repo 21 | 22 | 23 | 24 | 25 | 26 | org.example 27 | example-api 28 | 1.7.30 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/parent-version-is-property/child/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | child 6 | 7 | child 8 | ${revision} 9 | Child 10 | 11 | 12 | com.example 13 | parent 14 | ${revision} 15 | ../pom.xml 16 | 17 | 18 | 19 | 20 | org.example 21 | example-api 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/parent-version-is-property/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | parent 7 | ${revision} 8 | 9 | pom 10 | parent 11 | Parent 12 | 13 | 14 | 1.0.0-SNAPSHOT 15 | 16 | 17 | 18 | 19 | 20 | org.example 21 | example-api 22 | 1.1.1 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/project-version-from-parent/child/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | child 6 | 7 | child 8 | Child 9 | 10 | 11 | com.example 12 | parent 13 | 2.0.0 14 | ../parent 15 | 16 | 17 | 18 | 19 | org.example 20 | example-api 21 | ${project.version} 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/project-version-from-parent/parent/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 6 | com.example 7 | top-parent 8 | 3.0.0 9 | ../top-parent 10 | 11 | 12 | 13 | com.example 14 | parent 15 | 2.0.0 16 | 17 | pom 18 | parent 19 | Parent 20 | 21 | 22 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/project-version-from-parent/top-parent/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | top-parent 7 | 3.0.0 8 | 9 | pom 10 | top-parent 11 | Parent 12 | 13 | 14 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/repository/org/example/example-api/1.7.30/example-api-1.7.30.pom: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 4.0.0 7 | 8 | org.example 9 | example-api 10 | 1.7.30 11 | 12 | jar 13 | Example API Module 14 | The example API 15 | 16 | 17 | 18 | The Apache Software License, Version 2.0 19 | http://www.apache.org/licenses/LICENSE-2.0.txt 20 | repo 21 | 22 | 23 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/repository/org/example/example-api/2.0.0/example-api-2.0.0.pom: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 4.0.0 7 | 8 | org.example 9 | example-api 10 | 2.0.0 11 | 12 | jar 13 | Example API Module 14 | The example API 15 | 16 | 17 | 18 | The Apache Software License, Version 2.0 19 | http://www.apache.org/licenses/LICENSE-2.0.txt 20 | repo 21 | 22 | 23 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/repository/org/example/example-bom/1.0.0/example-bom-1.0.0.pom: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | org.example 6 | example-bom 7 | 1.0.0 8 | 9 | pom 10 | example-bom 11 | Example Bom 12 | 13 | 14 | 15 | 16 | org.example 17 | example-api 18 | 1.7.30 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/repository/org/example/example-bom/2.0.0/example-bom-2.0.0.pom: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | org.example 6 | example-bom 7 | 2.0.0 8 | 9 | pom 10 | example-bom 11 | Example Bom 12 | 13 | 14 | 15 | 16 | org.example 17 | example-api 18 | 2.0.0 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/repository/org/example/example-bom/3.0.0/example-bom-3.0.0.pom: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | org.example 6 | example-bom 7 | 3.0.0 8 | 9 | pom 10 | example-bom 11 | Example Bom 12 | 13 | 14 | 3.0.0 15 | 16 | 17 | 18 | 19 | 20 | org.example 21 | example-api 22 | ${api.version} 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/repository/org/example/example-bom/4.0.0/example-bom-4.0.0.pom: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | org.example 6 | example-bom 7 | 4.0.0 8 | 9 | pom 10 | example-bom 11 | Example Bom 12 | 13 | 14 | 4.0.0 15 | 16 | 17 | 18 | 19 | 20 | org.example 21 | example-api 22 | ${api.version} 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/repository/org/example/example-child-parent/2.0.0/example-child-parent-2.0.0.pom: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | org.example 6 | example-child-parent 7 | 2.0.0 8 | 9 | pom 10 | example-child-parent 11 | Child-Parent 12 | 13 | 14 | 15 | 16 | org.example 17 | example-api 18 | 2.7.30 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/repository/org/example/example-child/2.0.0/example-child-2.0.0.pom: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | org.example 6 | example-child 7 | 2.0.0 8 | 9 | pom 10 | example-child 11 | example-child-parent 12 | 13 | 14 | org.example 15 | example-child-parent 16 | 2.0.0 17 | 18 | 19 | 20 | 21 | Apache 2.0 22 | http://www.apache.org/licenses/LICENSE-2.0.html 23 | repo 24 | 25 | 26 | 27 | 28 | 29 | org.example 30 | example-api 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/repository/org/example/example-dependency-management/2.2.2/example-dependency-management-2.2.2.pom: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 4.0.0 6 | 7 | org.example 8 | example-dependency-management 9 | 2.2.2 10 | 11 | pom 12 | Example API Dependency Management 13 | The example API 14 | 15 | 16 | 17 | 18 | org.example 19 | example-api 20 | 1.7.30 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/repository/org/example/example-dependency-management/3.3.3/example-dependency-management-3.3.3.pom: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 4.0.0 6 | 7 | org.example 8 | example-dependency-management 9 | 3.3.3 10 | 11 | pom 12 | Example API Dependency Management 13 | The example API 14 | 15 | 16 | 1.1.1 17 | 18 | 19 | 20 | 21 | 22 | org.example 23 | example-dependency-management2 24 | ${project.managed.version} 25 | import 26 | pom 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.example 34 | example-dependency 35 | 1.2.3 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/repository/org/example/example-dependency-management2/1.1.1/example-dependency-management2-1.1.1.pom: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 4.0.0 6 | 7 | org.example 8 | example-dependency-management2 9 | 1.1.1 10 | 11 | pom 12 | Example API Dependency Management 13 | The example API 14 | 15 | 16 | 1.7.30 17 | 18 | 19 | 20 | 21 | 22 | org.example 23 | example-api 24 | ${project.managed.version} 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/repository/org/example/example-dependency-management3/1.1.1/example-dependency-management3-1.1.1.pom: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 4.0.0 6 | 7 | org.example 8 | example-dependency-management3 9 | 1.1.1 10 | 11 | pom 12 | Example API Dependency Management 13 | The example API 14 | 15 | 16 | 17 | 18 | 19 | org.example 20 | example-api 21 | 1.7.30 22 | 23 | 24 | 25 | 26 | 27 | 28 | org.example 29 | example-dependency 30 | 1.2.3 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/repository/org/example/example-dependency/1.2.3/example-dependency-1.2.3.pom: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 4.0.0 6 | 7 | org.example 8 | example-dependency 9 | 1.2.3 10 | 11 | jar 12 | Example API Dependency 13 | The example API 14 | 15 | 16 | 17 | org.example 18 | example-api 19 | 2.0.0 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/repository/org/example/example-dependency/1.2.4/example-dependency-1.2.4.pom: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 4.0.0 6 | 7 | org.example 8 | example-dependency 9 | 1.2.3 10 | 11 | jar 12 | Example API Dependency 13 | The example API 14 | 15 | 16 | 17 | org.example 18 | example-api 19 | [2.0.0] 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/repository/org/example/example-dependency2/2.3.4/example-dependency2-2.3.4.pom: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 4.0.0 6 | 7 | org.example 8 | example-dependency2 9 | 2.3.4 10 | 11 | jar 12 | Example API Dependency 13 | The example API 14 | 15 | 16 | 17 | org.example 18 | example-api 19 | 1.7.30 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/repository/org/example/example-exclusions/4.0.0/example-exclusions-4.0.0.pom: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | org.example 6 | example-exclusions 7 | 4.0.0 8 | 9 | 10 | 11 | org.example 12 | example-dependency 13 | 1.2.3 14 | 15 | 16 | org.example 17 | example-api 18 | 19 | 20 | 21 | 22 | org.example 23 | example-api 24 | 1.7.30 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/repository/org/example/example-nested/3.3.3/example-nested-3.3.3.pom: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 4.0.0 6 | 7 | org.example 8 | example-nested 9 | 3.3.3 10 | 11 | jar 12 | Example API Dependency 13 | The example API 14 | 15 | 16 | 17 | org.example 18 | example-dependency 19 | 1.2.3 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/repository/org/example/example-nested/3.3.4/example-nested-3.3.4.pom: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 4.0.0 6 | 7 | org.example 8 | example-nested 9 | 3.3.4 10 | 11 | jar 12 | Example API Dependency 13 | The example API 14 | 15 | 16 | 17 | org.example 18 | example-dependency 19 | [1.2.3] 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/repository/org/example/example-parent/1.0.0/example-parent-1.0.0.pom: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 4.0.0 6 | 7 | org.example 8 | example-parent 9 | 1.0.0 10 | 11 | pom 12 | Example API Parent 13 | The example API 14 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/root-pom-dep-management/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | root-pom-dep-management 7 | 1.0.0 8 | 9 | 10 | 11 | 12 | org.example 13 | example-dependency 14 | 1.2.4 15 | 16 | 17 | 18 | 19 | 20 | 21 | org.example 22 | example-nested 23 | 3.3.3 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/soft-requirement-with-transitive-dependencies/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | soft-transitive 7 | 1.0.0 8 | 9 | soft-transitive 10 | Example 11 | 12 | 13 | 14 | org.example 15 | example-dependency 16 | 1.2.3 17 | 18 | 19 | org.example 20 | example-dependency2 21 | 2.3.4 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/soft-requirement/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | soft 7 | 1.0.0 8 | 9 | soft 10 | Example 11 | 12 | 13 | 14 | Apache 2.0 15 | http://www.apache.org/licenses/LICENSE-2.0.html 16 | repo 17 | 18 | 19 | 20 | 21 | 22 | knqyf263 23 | https://github.com/knqyf263 24 | 25 | 26 | 27 | 28 | 1.7.30 29 | 30 | 31 | 32 | 33 | org.example 34 | example-api 35 | ${api.version} 36 | 37 | 38 | org.example 39 | example-dependency 40 | 1.2.3 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/transitive-dependency-management/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | org.example 6 | transitive-dependency-management 7 | 2.0.0 8 | 9 | jar 10 | Example 11 | Example 12 | 13 | 14 | 15 | org.example 16 | example-dependency-management3 17 | 1.1.1 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/transitive-parents/base/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | base 7 | 4.0.0 8 | 9 | base 10 | Base 11 | 12 | 13 | com.example 14 | parent 15 | 3.0.0 16 | ../parent 17 | 18 | 19 | 20 | 21 | Apache 2.0 22 | http://www.apache.org/licenses/LICENSE-2.0.html 23 | repo 24 | 25 | 26 | 27 | 28 | 29 | org.example 30 | example-child 31 | 2.0.0 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/transitive-parents/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | parent 7 | 3.0.0 8 | 9 | pom 10 | parent 11 | Parent 12 | 13 | 14 | 15 | Apache 2.0 16 | http://www.apache.org/licenses/LICENSE-2.0.html 17 | repo 18 | 19 | 20 | 21 | 22 | 23 | 24 | org.example 25 | example-api 26 | 1.7.30 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/version-requirement/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | hard 7 | 1.0.0 8 | 9 | soft 10 | Example 11 | 12 | 13 | 14 | Apache 2.0 15 | http://www.apache.org/licenses/LICENSE-2.0.html 16 | repo 17 | 18 | 19 | 20 | 21 | 22 | knqyf263 23 | https://github.com/knqyf263 24 | 25 | 26 | 27 | 28 | 29 | org.example 30 | example-api 31 | (,1.0] 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /pkg/java/pom/testdata/wildcard-exclusions/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.example 6 | wildcard-exclusions 7 | 4.0.0 8 | 9 | pom 10 | wildcard-exclusions 11 | Exclusions with wildcards 12 | 13 | 14 | 15 | org.example 16 | example-dependency 17 | 1.2.3 18 | 19 | 20 | * 21 | example-api 22 | 23 | 24 | 25 | 26 | org.example 27 | example-dependency2 28 | 2.3.4 29 | 30 | 31 | * 32 | * 33 | 34 | 35 | 36 | 37 | org.example 38 | example-nested 39 | 3.3.3 40 | 41 | 42 | org.example 43 | * 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /pkg/java/pom/utils.go: -------------------------------------------------------------------------------- 1 | package pom 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | ) 8 | 9 | func isDirectory(path string) (bool, error) { 10 | fileInfo, err := os.Stat(path) 11 | if err != nil { 12 | return false, err 13 | } 14 | return fileInfo.IsDir(), err 15 | } 16 | 17 | func isProperty(version string) bool { 18 | if version != "" && strings.HasPrefix(version, "${") && strings.HasSuffix(version, "}") { 19 | return true 20 | } 21 | return false 22 | } 23 | 24 | func packageID(name, version string) string { 25 | return fmt.Sprintf("%s:%s", name, version) 26 | } 27 | -------------------------------------------------------------------------------- /pkg/julia/manifest/naive_pkg_parser.go: -------------------------------------------------------------------------------- 1 | package julia 2 | 3 | import ( 4 | "bufio" 5 | "io" 6 | "strings" 7 | ) 8 | 9 | type pkgPosition struct { 10 | start int 11 | end int 12 | } 13 | type minPkg struct { 14 | uuid string 15 | version string 16 | position pkgPosition 17 | } 18 | 19 | func (pkg *minPkg) setEndPositionIfEmpty(n int) { 20 | if pkg.position.end == 0 { 21 | pkg.position.end = n 22 | } 23 | } 24 | 25 | type naivePkgParser struct { 26 | r io.Reader 27 | } 28 | 29 | func (parser *naivePkgParser) parse() map[string]pkgPosition { 30 | var currentPkg minPkg = minPkg{} 31 | var idx = make(map[string]pkgPosition, 0) 32 | 33 | scanner := bufio.NewScanner(parser.r) 34 | lineNum := 1 35 | for scanner.Scan() { 36 | line := scanner.Text() 37 | if strings.HasPrefix(strings.TrimSpace(line), "[") { 38 | if currentPkg.uuid != "" { 39 | currentPkg.setEndPositionIfEmpty(lineNum - 1) 40 | idx[currentPkg.uuid] = currentPkg.position 41 | } 42 | currentPkg = minPkg{} 43 | currentPkg.position.start = lineNum 44 | 45 | } else if strings.HasPrefix(strings.TrimSpace(line), "uuid =") { 46 | currentPkg.uuid = propertyValue(line) 47 | } else if strings.HasPrefix(strings.TrimSpace(line), "version =") { 48 | currentPkg.version = propertyValue(line) 49 | } else if strings.TrimSpace(line) == "" { 50 | currentPkg.setEndPositionIfEmpty(lineNum - 1) 51 | } 52 | 53 | lineNum++ 54 | } 55 | // add last item 56 | if currentPkg.uuid != "" { 57 | currentPkg.setEndPositionIfEmpty(lineNum - 1) 58 | idx[currentPkg.uuid] = currentPkg.position 59 | } 60 | return idx 61 | } 62 | func propertyValue(line string) string { 63 | parts := strings.Split(line, "=") 64 | if len(parts) == 2 { 65 | return strings.Trim(parts[1], ` "`) 66 | } 67 | return "" 68 | } 69 | -------------------------------------------------------------------------------- /pkg/julia/manifest/parse_test.go: -------------------------------------------------------------------------------- 1 | package julia 2 | 3 | import ( 4 | "os" 5 | "sort" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | "github.com/stretchr/testify/require" 10 | 11 | "github.com/aquasecurity/go-dep-parser/pkg/types" 12 | ) 13 | 14 | func TestParse(t *testing.T) { 15 | tests := []struct { 16 | name string 17 | file string // Test input file 18 | want []types.Library 19 | wantDeps []types.Dependency 20 | }{ 21 | { 22 | name: "Manifest v1.6", 23 | file: "testdata/primary/Manifest_v1.6.toml", 24 | want: juliaV1_6Libs, 25 | wantDeps: juliaV1_6Deps, 26 | }, 27 | { 28 | name: "Manifest v1.8", 29 | file: "testdata/primary/Manifest_v1.8.toml", 30 | want: juliaV1_8Libs, 31 | wantDeps: juliaV1_8Deps, 32 | }, 33 | { 34 | name: "no deps v1.6", 35 | file: "testdata/no_deps_v1.6/Manifest.toml", 36 | want: nil, 37 | wantDeps: nil, 38 | }, 39 | { 40 | name: "no deps v1.9", 41 | file: "testdata/no_deps_v1.9/Manifest.toml", 42 | want: nil, 43 | wantDeps: nil, 44 | }, 45 | { 46 | name: "dep extensions v1.9", 47 | file: "testdata/dep_ext_v1.9/Manifest.toml", 48 | want: juliaV1_9DepExtLibs, 49 | wantDeps: nil, 50 | }, 51 | { 52 | name: "shadowed dep v1.9", 53 | file: "testdata/shadowed_dep_v1.9/Manifest.toml", 54 | want: juliaV1_9ShadowedDepLibs, 55 | wantDeps: juliaV1_9ShadowedDepDeps, 56 | }, 57 | } 58 | 59 | for _, tt := range tests { 60 | t.Run(tt.name, func(t *testing.T) { 61 | f, err := os.Open(tt.file) 62 | require.NoError(t, err) 63 | 64 | gotLibs, gotDeps, err := NewParser().Parse(f) 65 | require.NoError(t, err) 66 | 67 | sort.Sort(types.Libraries(tt.want)) 68 | assert.Equal(t, tt.want, gotLibs) 69 | if tt.wantDeps != nil { 70 | sort.Sort(types.Dependencies(tt.wantDeps)) 71 | assert.Equal(t, tt.wantDeps, gotDeps) 72 | } 73 | }) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /pkg/julia/manifest/testdata/dep_ext_v1.9/Manifest.toml: -------------------------------------------------------------------------------- 1 | # This file is machine-generated - editing it directly is not advised 2 | 3 | julia_version = "1.9.0" 4 | manifest_format = "2.0" 5 | project_hash = "f0a796fb78285c02ad123fec6e14c8bac09a2ccc" 6 | 7 | [[deps.AbstractFFTs]] 8 | git-tree-sha1 = "16b6dbc4cf7caee4e1e75c49485ec67b667098a0" 9 | uuid = "621f4979-c628-5d54-868e-fcf4e3e8185c" 10 | version = "1.3.1" 11 | 12 | [deps.AbstractFFTs.extensions] 13 | AbstractFFTsChainRulesCoreExt = "ChainRulesCore" 14 | 15 | [deps.AbstractFFTs.weakdeps] 16 | ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" 17 | -------------------------------------------------------------------------------- /pkg/julia/manifest/testdata/no_deps_v1.6/Manifest.toml: -------------------------------------------------------------------------------- 1 | # This file is machine-generated - editing it directly is not advised 2 | 3 | -------------------------------------------------------------------------------- /pkg/julia/manifest/testdata/no_deps_v1.9/Manifest.toml: -------------------------------------------------------------------------------- 1 | # This file is machine-generated - editing it directly is not advised 2 | 3 | julia_version = "1.9.0" 4 | manifest_format = "2.0" 5 | project_hash = "da39a3ee5e6b4b0d3255bfef95601890afd80709" 6 | 7 | [deps] 8 | -------------------------------------------------------------------------------- /pkg/julia/manifest/testdata/primary/Manifest_v1.6.toml: -------------------------------------------------------------------------------- 1 | # This file is machine-generated - editing it directly is not advised 2 | 3 | [[Dates]] 4 | deps = ["Printf"] 5 | uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" 6 | 7 | [[JSON]] 8 | deps = ["Dates", "Mmap", "Parsers", "Unicode"] 9 | git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a" 10 | uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" 11 | version = "0.21.4" 12 | 13 | [[Mmap]] 14 | uuid = "a63ad114-7e13-5084-954f-fe012c677804" 15 | 16 | [[Parsers]] 17 | deps = ["Dates"] 18 | git-tree-sha1 = "6c01a9b494f6d2a9fc180a08b182fcb06f0958a0" 19 | uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" 20 | version = "2.4.2" 21 | 22 | [[Printf]] 23 | deps = ["Unicode"] 24 | uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" 25 | 26 | [[Unicode]] 27 | uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" 28 | -------------------------------------------------------------------------------- /pkg/julia/manifest/testdata/primary/Manifest_v1.8.toml: -------------------------------------------------------------------------------- 1 | # This file is machine-generated - editing it directly is not advised 2 | 3 | julia_version = "1.8.5" 4 | manifest_format = "2.0" 5 | project_hash = "f65b9de676a27ce78ee011db6d477b3d44d1a7c5" 6 | 7 | [[deps.Dates]] 8 | deps = ["Printf"] 9 | uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" 10 | 11 | [[deps.JSON]] 12 | deps = ["Dates", "Mmap", "Parsers", "Unicode"] 13 | git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a" 14 | uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" 15 | version = "0.21.4" 16 | 17 | [[deps.Mmap]] 18 | uuid = "a63ad114-7e13-5084-954f-fe012c677804" 19 | 20 | [[deps.Parsers]] 21 | deps = ["Dates", "PrecompileTools", "UUIDs"] 22 | git-tree-sha1 = "a5aef8d4a6e8d81f171b2bd4be5265b01384c74c" 23 | uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" 24 | version = "2.5.10" 25 | 26 | [[deps.PrecompileTools]] 27 | deps = ["Preferences"] 28 | git-tree-sha1 = "259e206946c293698122f63e2b513a7c99a244e8" 29 | uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a" 30 | version = "1.1.1" 31 | 32 | [[deps.Preferences]] 33 | deps = ["TOML"] 34 | git-tree-sha1 = "7eb1686b4f04b82f96ed7a4ea5890a4f0c7a09f1" 35 | uuid = "21216c6a-2e73-6563-6e65-726566657250" 36 | version = "1.4.0" 37 | 38 | [[deps.Printf]] 39 | deps = ["Unicode"] 40 | uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" 41 | 42 | [[deps.Random]] 43 | deps = ["SHA", "Serialization"] 44 | uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" 45 | 46 | [[deps.SHA]] 47 | uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" 48 | version = "0.7.0" 49 | 50 | [[deps.Serialization]] 51 | uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" 52 | 53 | [[deps.TOML]] 54 | deps = ["Dates"] 55 | uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" 56 | version = "1.0.0" 57 | 58 | [[deps.UUIDs]] 59 | deps = ["Random", "SHA"] 60 | uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" 61 | 62 | [[deps.Unicode]] 63 | uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" 64 | -------------------------------------------------------------------------------- /pkg/julia/manifest/testdata/shadowed_dep_v1.9/Manifest.toml: -------------------------------------------------------------------------------- 1 | # This file is machine-generated - editing it directly is not advised 2 | 3 | julia_version = "1.9.0" 4 | manifest_format = "2.0" 5 | project_hash = "f0a796fb78285c02ad123fec6e14c8bac09a2ccc" 6 | 7 | [[deps.A]] 8 | uuid = "ead4f63c-334e-11e9-00e6-e7f0a5f21b60" 9 | 10 | [deps.A.deps] 11 | B = "f41f7b98-334e-11e9-1257-49272045fb24" 12 | 13 | [[deps.B]] 14 | uuid = "f41f7b98-334e-11e9-1257-49272045fb24" 15 | [[deps.B]] 16 | uuid = "edca9bc6-334e-11e9-3554-9595dbb4349c" 17 | -------------------------------------------------------------------------------- /pkg/log/log.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | "go.uber.org/zap" 5 | ) 6 | 7 | var Logger *zap.SugaredLogger 8 | 9 | func init() { 10 | config := zap.Config{ 11 | Level: zap.NewAtomicLevelAt(zap.InfoLevel), 12 | Development: false, 13 | Encoding: "console", 14 | EncoderConfig: zap.NewDevelopmentEncoderConfig(), 15 | OutputPaths: []string{"stderr"}, 16 | ErrorOutputPaths: []string{"stderr"}, 17 | } 18 | logger, _ := config.Build() 19 | Logger = logger.Sugar() 20 | } 21 | 22 | func SetLogger(l *zap.SugaredLogger) { 23 | Logger = l 24 | } 25 | -------------------------------------------------------------------------------- /pkg/nodejs/npm/parse_test.go: -------------------------------------------------------------------------------- 1 | package npm 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/stretchr/testify/require" 9 | 10 | "github.com/aquasecurity/go-dep-parser/pkg/types" 11 | ) 12 | 13 | func TestParse(t *testing.T) { 14 | tests := []struct { 15 | name string 16 | file string // Test input file 17 | want []types.Library 18 | wantDeps []types.Dependency 19 | }{ 20 | { 21 | name: "lock version v1", 22 | file: "testdata/package-lock_v1.json", 23 | want: npmV1Libs, 24 | wantDeps: npmDeps, 25 | }, 26 | { 27 | name: "lock version v2", 28 | file: "testdata/package-lock_v2.json", 29 | want: npmV2Libs, 30 | wantDeps: npmDeps, 31 | }, 32 | { 33 | name: "lock version v3", 34 | file: "testdata/package-lock_v3.json", 35 | want: npmV2Libs, 36 | wantDeps: npmDeps, 37 | }, 38 | { 39 | name: "lock version v3 with workspace", 40 | file: "testdata/package-lock_v3_with_workspace.json", 41 | want: npmV3WithWorkspaceLibs, 42 | wantDeps: npmV3WithWorkspaceDeps, 43 | }, 44 | { 45 | name: "lock version v3 with workspace and without direct deps field", 46 | file: "testdata/package-lock_v3_without_root_deps_field.json", 47 | want: npmV3WithoutRootDepsField, 48 | wantDeps: npmV3WithoutRootDepsFieldDeps, 49 | }, 50 | } 51 | 52 | for _, tt := range tests { 53 | t.Run(tt.name, func(t *testing.T) { 54 | f, err := os.Open(tt.file) 55 | require.NoError(t, err) 56 | 57 | got, deps, err := NewParser().Parse(f) 58 | require.NoError(t, err) 59 | 60 | assert.Equal(t, tt.want, got) 61 | if tt.wantDeps != nil { 62 | assert.Equal(t, tt.wantDeps, deps) 63 | } 64 | }) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /pkg/nodejs/npm/testdata/package-lock_v3_without_root_deps_field.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node_v3_without_direct_deps", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "node_v3_without_direct_deps", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "workspaces": [ 12 | "functions/func1" 13 | ] 14 | }, 15 | "functions/func1": { 16 | "version": "1.0.0", 17 | "license": "ISC", 18 | "dependencies": { 19 | "debug": "^2.6.9" 20 | } 21 | }, 22 | "node_modules/debug": { 23 | "version": "2.6.9", 24 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 25 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 26 | "dependencies": { 27 | "ms": "2.0.0" 28 | } 29 | }, 30 | "node_modules/func1": { 31 | "resolved": "functions/func1", 32 | "link": true 33 | }, 34 | "node_modules/ms": { 35 | "version": "2.0.0", 36 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 37 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /pkg/nodejs/packagejson/testdata/invalid_package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" "bootstrap" 3 | } -------------------------------------------------------------------------------- /pkg/nodejs/packagejson/testdata/without_name_and_version_package.json: -------------------------------------------------------------------------------- 1 | { 2 | "license": "MIT" 3 | } 4 | -------------------------------------------------------------------------------- /pkg/nodejs/packagejson/testdata/without_version_package.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "name": "angular" 4 | } 5 | -------------------------------------------------------------------------------- /pkg/nodejs/pnpm/testdata/pnpm-lock_archives.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | dependencies: 4 | debug: 5 | specifier: https://github.com/debug-js/debug/tarball/4.3.4 6 | version: '@github.com/debug-js/debug/tarball/4.3.4' 7 | is-negative: 8 | specifier: https://codeload.github.com/zkochan/is-negative/tar.gz/2fa0531ab04e300a24ef4fd7fb3a280eccb7ccc5 9 | version: '@codeload.github.com/zkochan/is-negative/tar.gz/2fa0531ab04e300a24ef4fd7fb3a280eccb7ccc5' 10 | lodash: 11 | specifier: file:foo/bar/lodash.tgz 12 | version: file:foo/bar/lodash.tgz 13 | package1: 14 | specifier: file:package1 15 | version: file:package1 16 | 17 | packages: 18 | 19 | /asynckit@0.4.0: 20 | resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} 21 | dev: false 22 | 23 | /ms@2.1.2: 24 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 25 | dev: false 26 | 27 | '@codeload.github.com/zkochan/is-negative/tar.gz/2fa0531ab04e300a24ef4fd7fb3a280eccb7ccc5': 28 | resolution: {tarball: https://codeload.github.com/zkochan/is-negative/tar.gz/2fa0531ab04e300a24ef4fd7fb3a280eccb7ccc5} 29 | name: is-negative 30 | version: 2.0.1 31 | engines: {node: '>=0.10.0'} 32 | dev: false 33 | 34 | '@github.com/debug-js/debug/tarball/4.3.4': 35 | resolution: {tarball: https://github.com/debug-js/debug/tarball/4.3.4} 36 | name: debug 37 | version: 4.3.4 38 | engines: {node: '>=6.0'} 39 | peerDependencies: 40 | supports-color: '*' 41 | peerDependenciesMeta: 42 | supports-color: 43 | optional: true 44 | dependencies: 45 | ms: 2.1.2 46 | dev: false 47 | 48 | file:foo/bar/lodash.tgz: 49 | resolution: {integrity: sha512-fPftOkGbplay6FszUHWPJ8wV7liS+n2gB/UVN0Wv4G71KJWx+8trhGYsbekWqz6TTzkKur67bAdSIIccmKIyLA==, tarball: file:foo/bar/lodash.tgz} 50 | name: lodash 51 | version: 4.17.21 52 | dev: false 53 | 54 | file:package1: 55 | resolution: {directory: package1, type: directory} 56 | name: package1 57 | version: 1.0.0 58 | dependencies: 59 | asynckit: 0.4.0 60 | dev: false 61 | -------------------------------------------------------------------------------- /pkg/nodejs/pnpm/testdata/pnpm-lock_normal.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: 5.3 2 | 3 | specifiers: 4 | jquery: ^3.6.0 5 | promise: ^8.1.0 6 | 7 | dependencies: 8 | jquery: 3.6.0 9 | promise: 8.1.0 10 | 11 | packages: 12 | 13 | /asap/2.0.6: 14 | resolution: {integrity: sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=} 15 | dev: false 16 | 17 | /jquery/3.6.0: 18 | resolution: {integrity: sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==} 19 | dev: false 20 | 21 | /promise/8.1.0: 22 | resolution: {integrity: sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==} 23 | dependencies: 24 | asap: 2.0.6 25 | dev: false -------------------------------------------------------------------------------- /pkg/nodejs/pnpm/testdata/pnpm-lock_v6.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | dependencies: 4 | jquery: 5 | specifier: 3.6.0 6 | version: 3.6.0 7 | promise: 8 | specifier: 8.1.0 9 | version: 8.1.0 10 | 11 | packages: 12 | 13 | /asap@2.0.6: 14 | resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} 15 | dev: false 16 | 17 | /jquery@3.6.0: 18 | resolution: {integrity: sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==} 19 | dev: false 20 | 21 | /promise@8.1.0: 22 | resolution: {integrity: sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==} 23 | dependencies: 24 | asap: 2.0.6 25 | dev: false 26 | -------------------------------------------------------------------------------- /pkg/nodejs/yarn/testcase_deps_generator/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14-alpine 2 | 3 | COPY index.js /test_deps_generator/index.js 4 | COPY yarn.lock /test_deps_generator/yarn.lock 5 | COPY package.json /test_deps_generator/package.json -------------------------------------------------------------------------------- /pkg/nodejs/yarn/testcase_deps_generator/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lock-parser", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "dependencies": { 7 | "@yarnpkg/lockfile": "^1.1.0", 8 | "yaml": "^2.1.3" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /pkg/nodejs/yarn/testcase_deps_generator/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@yarnpkg/lockfile@^1.1.0": 6 | version "1.1.0" 7 | resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" 8 | integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== 9 | 10 | yaml@^2.1.3: 11 | version "2.1.3" 12 | resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.1.3.tgz#9b3a4c8aff9821b696275c79a8bee8399d945207" 13 | integrity sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg== 14 | -------------------------------------------------------------------------------- /pkg/nodejs/yarn/testdata/yarn_normal.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | asap@~2.0.6: 6 | version "2.0.6" 7 | resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" 8 | integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= 9 | 10 | jquery@^3.4.1: 11 | version "3.4.1" 12 | resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.4.1.tgz#714f1f8d9dde4bdfa55764ba37ef214630d80ef2" 13 | integrity sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw== 14 | 15 | promise@^8.0.3: 16 | version "8.0.3" 17 | resolved "https://registry.yarnpkg.com/promise/-/promise-8.0.3.tgz#f592e099c6cddc000d538ee7283bb190452b0bf6" 18 | integrity sha512-HeRDUL1RJiLhyA0/grn+PTShlBAcLuh/1BJGtrvjwbvRDCTLLMEz9rOGCV+R3vHY4MixIuoMEd9Yq/XvsTPcjw== 19 | dependencies: 20 | asap "~2.0.6" 21 | -------------------------------------------------------------------------------- /pkg/nodejs/yarn/testdata/yarn_v2_deps_with_protocol.lock: -------------------------------------------------------------------------------- 1 | # This file is generated by running "yarn install" inside your project. 2 | # Manual changes might be lost - proceed with caution! 3 | 4 | __metadata: 5 | version: 8 6 | cacheKey: 10c0 7 | 8 | "app@workspace:.": 9 | version: 0.0.0-use.local 10 | resolution: "app@workspace:." 11 | dependencies: 12 | debug: "npm:4.3.4" 13 | languageName: unknown 14 | linkType: soft 15 | 16 | "debug@npm:4.3.4": 17 | version: 4.3.4 18 | resolution: "debug@npm:4.3.4" 19 | dependencies: 20 | ms: "npm:2.1.2" 21 | peerDependenciesMeta: 22 | supports-color: 23 | optional: true 24 | checksum: cedbec45298dd5c501d01b92b119cd3faebe5438c3917ff11ae1bff86a6c722930ac9c8659792824013168ba6db7c4668225d845c633fbdafbbf902a6389f736 25 | languageName: node 26 | linkType: hard 27 | 28 | "ms@npm:2.1.2": 29 | version: 2.1.2 30 | resolution: "ms@npm:2.1.2" 31 | checksum: a437714e2f90dbf881b5191d35a6db792efbca5badf112f87b9e1c712aace4b4b9b742dd6537f3edf90fd6f684de897cec230abde57e87883766712ddda297cc 32 | languageName: node 33 | linkType: hard 34 | -------------------------------------------------------------------------------- /pkg/nodejs/yarn/testdata/yarn_v2_normal.lock: -------------------------------------------------------------------------------- 1 | # This file is generated by running "yarn install" inside your project. 2 | # Manual changes might be lost - proceed with caution! 3 | 4 | __metadata: 5 | version: 4 6 | cacheKey: 6 7 | 8 | "asap@npm:~2.0.6": 9 | version: 2.0.6 10 | resolution: "asap@npm:2.0.6" 11 | checksum: 3d314f8c598b625a98347bacdba609d4c889c616ca5d8ea65acaae8050ab8b7aa6630df2cfe9856c20b260b432adf2ee7a65a1021f268ef70408c70f809e3a39 12 | languageName: node 13 | linkType: hard 14 | 15 | "code@workspace:.": 16 | version: 0.0.0-use.local 17 | resolution: "code@workspace:." 18 | dependencies: 19 | jquery: ^3.5.1 20 | promise: ^8.1.0 21 | languageName: unknown 22 | linkType: soft 23 | 24 | "jquery@npm:^3.5.1": 25 | version: 3.5.1 26 | resolution: "jquery@npm:3.5.1" 27 | checksum: c50818c84837902a60938c85786feb612f346a9918f7285409d605449460790b3815ad8aaf5806f19e89f1a79b27d327802b421ab354fe213f3fd1801e3562e6 28 | languageName: node 29 | linkType: hard 30 | 31 | "promise@npm:^8.1.0": 32 | version: 8.1.0 33 | resolution: "promise@npm:8.1.0" 34 | dependencies: 35 | asap: ~2.0.6 36 | checksum: ec94008d8a673c276dbc7722c215f583026b8d2588fb83f40e69908c553801eac7fbe3034c9bca853d5c422af20826abdfb9391b982a888868d9c88281dc59fb 37 | languageName: node 38 | linkType: hard -------------------------------------------------------------------------------- /pkg/nodejs/yarn/testdata/yarn_with_bad_protocol.lock: -------------------------------------------------------------------------------- 1 | asap@unsupported:~2.0.6: 2 | version "2.0.6" 3 | 4 | jquery@^3.4.1: 5 | version "3.4.1" 6 | resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.4.1.tgz#714f1f8d9dde4bdfa55764ba37ef214630d80ef2" 7 | integrity sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw== -------------------------------------------------------------------------------- /pkg/nodejs/yarn/testdata/yarn_with_git.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "mapbox-gl-feature-drag-and-drop@git+https://github.com/jrd/mapbox-gl-feature-drag-and-drop.git": 6 | version "1.1.1" 7 | resolved "git+https://github.com/jrd/mapbox-gl-feature-drag-and-drop.git#538b1126e0d15210e91b4a34ffc223b4fec1ef87" -------------------------------------------------------------------------------- /pkg/nodejs/yarn/testdata/yarn_with_local.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | asap@~2.0.6: 6 | version "2.0.6" 7 | resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" 8 | integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= 9 | 10 | jquery@^3.4.1: 11 | version "3.4.1" 12 | resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.4.1.tgz#714f1f8d9dde4bdfa55764ba37ef214630d80ef2" 13 | integrity sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw== 14 | 15 | promise@^8.0.3: 16 | version "8.0.3" 17 | resolved "https://registry.yarnpkg.com/promise/-/promise-8.0.3.tgz#f592e099c6cddc000d538ee7283bb190452b0bf6" 18 | integrity sha512-HeRDUL1RJiLhyA0/grn+PTShlBAcLuh/1BJGtrvjwbvRDCTLLMEz9rOGCV+R3vHY4MixIuoMEd9Yq/XvsTPcjw== 19 | dependencies: 20 | asap "~2.0.6" 21 | 22 | "local-package@file:vendor/local-package.tar.gz": 23 | version "0.0.1" 24 | resolved "file:vendor/local-package.tar.gz#f0b5161c241e8c94acc6241c49e3ab6806e6d4d7" -------------------------------------------------------------------------------- /pkg/nodejs/yarn/testdata/yarn_with_npm.lock: -------------------------------------------------------------------------------- 1 | "jquery@^3.6.0": 2 | "integrity" "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==" 3 | "resolved" "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz" 4 | "version" "3.6.0" -------------------------------------------------------------------------------- /pkg/nuget/config/parse.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "encoding/xml" 5 | 6 | "golang.org/x/xerrors" 7 | 8 | dio "github.com/aquasecurity/go-dep-parser/pkg/io" 9 | "github.com/aquasecurity/go-dep-parser/pkg/types" 10 | "github.com/aquasecurity/go-dep-parser/pkg/utils" 11 | ) 12 | 13 | type cfgPackageReference struct { 14 | XMLName xml.Name `xml:"package"` 15 | TargetFramework string `xml:"targetFramework,attr"` 16 | Version string `xml:"version,attr"` 17 | DevDependency bool `xml:"developmentDependency,attr"` 18 | ID string `xml:"id,attr"` 19 | } 20 | 21 | type config struct { 22 | XMLName xml.Name `xml:"packages"` 23 | Packages []cfgPackageReference `xml:"package"` 24 | } 25 | 26 | type Parser struct{} 27 | 28 | func NewParser() types.Parser { 29 | return &Parser{} 30 | } 31 | 32 | func (p *Parser) Parse(r dio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { 33 | var cfgData config 34 | if err := xml.NewDecoder(r).Decode(&cfgData); err != nil { 35 | return nil, nil, xerrors.Errorf("failed to decode .config file: %w", err) 36 | } 37 | 38 | libs := make([]types.Library, 0) 39 | for _, pkg := range cfgData.Packages { 40 | if pkg.ID == "" || pkg.DevDependency { 41 | continue 42 | } 43 | 44 | lib := types.Library{ 45 | Name: pkg.ID, 46 | Version: pkg.Version, 47 | } 48 | 49 | libs = append(libs, lib) 50 | } 51 | 52 | return utils.UniqueLibraries(libs), nil, nil 53 | } 54 | -------------------------------------------------------------------------------- /pkg/nuget/config/parse_test.go: -------------------------------------------------------------------------------- 1 | package config_test 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/stretchr/testify/require" 9 | 10 | "github.com/aquasecurity/go-dep-parser/pkg/nuget/config" 11 | "github.com/aquasecurity/go-dep-parser/pkg/types" 12 | ) 13 | 14 | func TestParse(t *testing.T) { 15 | tests := []struct { 16 | name string // Test input file 17 | inputFile string 18 | want []types.Library 19 | wantErr string 20 | }{ 21 | { 22 | name: "Config", 23 | inputFile: "testdata/packages.config", 24 | want: []types.Library{ 25 | {Name: "Newtonsoft.Json", Version: "6.0.4"}, 26 | {Name: "Microsoft.AspNet.WebApi", Version: "5.2.2"}, 27 | }, 28 | }, 29 | { 30 | name: "with development dependency", 31 | inputFile: "testdata/dev_dependency.config", 32 | want: []types.Library{ 33 | {Name: "Newtonsoft.Json", Version: "8.0.3"}, 34 | }, 35 | }, 36 | { 37 | name: "sad path", 38 | inputFile: "testdata/malformed_xml.config", 39 | wantErr: "failed to decode .config file: XML syntax error on line 5: unexpected EOF", 40 | }, 41 | } 42 | for _, tt := range tests { 43 | t.Run(tt.name, func(t *testing.T) { 44 | f, err := os.Open(tt.inputFile) 45 | require.NoError(t, err) 46 | 47 | got, _, err := config.NewParser().Parse(f) 48 | if tt.wantErr != "" { 49 | require.NotNil(t, err) 50 | assert.Contains(t, err.Error(), tt.wantErr) 51 | return 52 | } 53 | 54 | assert.NoError(t, err) 55 | assert.ElementsMatch(t, tt.want, got) 56 | }) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /pkg/nuget/config/testdata/dev_dependency.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /pkg/nuget/config/testdata/malformed_xml.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /pkg/nuget/config/testdata/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /pkg/nuget/lock/parse_test.go: -------------------------------------------------------------------------------- 1 | package lock 2 | 3 | import ( 4 | "os" 5 | "path" 6 | "sort" 7 | "strings" 8 | "testing" 9 | 10 | "github.com/stretchr/testify/assert" 11 | "github.com/stretchr/testify/require" 12 | 13 | "github.com/aquasecurity/go-dep-parser/pkg/types" 14 | ) 15 | 16 | func TestParse(t *testing.T) { 17 | vectors := []struct { 18 | file string // Test input file 19 | want []types.Library 20 | wantDeps []types.Dependency 21 | }{ 22 | { 23 | file: "testdata/packages_lock_simple.json", 24 | want: nuGetSimple, 25 | wantDeps: nuGetSimpleDeps, 26 | }, 27 | { 28 | file: "testdata/packages_lock_subdependencies.json", 29 | want: nuGetSubDependencies, 30 | wantDeps: nuGetSubDependenciesDeps, 31 | }, 32 | { 33 | file: "testdata/packages_lock_multi.json", 34 | want: nuGetMultiTarget, 35 | wantDeps: nuGetMultiTargetDeps, 36 | }, 37 | { 38 | file: "testdata/packages_lock_legacy.json", 39 | want: nuGetLegacy, 40 | wantDeps: nuGetLegacyDeps, 41 | }, 42 | } 43 | 44 | for _, v := range vectors { 45 | t.Run(path.Base(v.file), func(t *testing.T) { 46 | f, err := os.Open(v.file) 47 | require.NoError(t, err) 48 | 49 | got, deps, err := NewParser().Parse(f) 50 | require.NoError(t, err) 51 | 52 | sort.Slice(got, func(i, j int) bool { 53 | ret := strings.Compare(got[i].Name, got[j].Name) 54 | if ret == 0 { 55 | return got[i].Version < got[j].Version 56 | } 57 | return ret < 0 58 | }) 59 | 60 | sort.Slice(v.want, func(i, j int) bool { 61 | ret := strings.Compare(v.want[i].Name, v.want[j].Name) 62 | if ret == 0 { 63 | return v.want[i].Version < v.want[j].Version 64 | } 65 | return ret < 0 66 | }) 67 | 68 | assert.Equal(t, v.want, got) 69 | 70 | if v.wantDeps != nil { 71 | sortDeps(deps) 72 | sortDeps(v.wantDeps) 73 | assert.Equal(t, v.wantDeps, deps) 74 | } 75 | }) 76 | } 77 | } 78 | 79 | func sortDeps(deps []types.Dependency) { 80 | sort.Slice(deps, func(i, j int) bool { 81 | return strings.Compare(deps[i].ID, deps[j].ID) < 0 82 | }) 83 | 84 | for i := range deps { 85 | sort.Strings(deps[i].DependsOn) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /pkg/nuget/lock/testdata/packages_lock_legacy.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "dependencies": { 4 | ".NETCoreApp,Version=v5.0": { 5 | "AWSSDK.Core": { 6 | "type": "Direct", 7 | "requested": "[3.5.1.30, )", 8 | "resolved": "3.5.1.30", 9 | "contentHash": "kNqzY/py4pDlW9aPn2SpnG7y7Mr4Z0jg/BdkHiRr9WLt7k/lwGMmJ5hd3x/ZHDkv8kIdjllkVrrhYkXvj6AkCA==" 10 | }, 11 | "Newtonsoft.Json": { 12 | "type": "Direct", 13 | "requested": "[12.0.3, )", 14 | "resolved": "12.0.3", 15 | "contentHash": "6mgjfnRB4jKMlzHSl+VD+oUc1IebOZabkbyWj2RiTgWwYPPuaK1H97G1sHqGwPlS5npiF5Q0OrxN1wni2n5QWg==" 16 | }, 17 | "my.project": { 18 | "type": "Project", 19 | "dependencies": { 20 | "Newtonsoft.Json": "12.0.3", 21 | "AWSSDK.Core": "3.5.1.30" 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /pkg/nuget/lock/testdata/packages_lock_simple.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "dependencies": { 4 | ".NETCoreApp,Version=v5.0": { 5 | "Newtonsoft.Json": { 6 | "type": "Direct", 7 | "requested": "[12.0.3, )", 8 | "resolved": "12.0.3", 9 | "contentHash": "6mgjfnRB4jKMlzHSl+VD+oUc1IebOZabkbyWj2RiTgWwYPPuaK1H97G1sHqGwPlS5npiF5Q0OrxN1wni2n5QWg==" 10 | }, 11 | "NuGet.Frameworks": { 12 | "type": "Direct", 13 | "requested": "[5.7.0, )", 14 | "resolved": "5.7.0", 15 | "contentHash": "7Q/wUoB3jCBcq9zoBOBGHFhe78C13jViPmvjvzTwthVV8DAjMfpXnqAYtgwdaRLJMkTXrtdLxfPBIFFhmlsnIQ==" 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /pkg/nuget/packagesprops/testdata/Directory.Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /pkg/nuget/packagesprops/testdata/no_item_group.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /pkg/nuget/packagesprops/testdata/no_project.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /pkg/nuget/packagesprops/testdata/packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /pkg/nuget/packagesprops/testdata/several_item_groups: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /pkg/nuget/packagesprops/testdata/variables_and_empty: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /pkg/python/packaging/testdata/distlib-0.3.1-py3.9.egg-info: -------------------------------------------------------------------------------- 1 | Metadata-Version: 1.1 2 | Name: distlib 3 | Version: 0.3.1 4 | Summary: Distribution utilities 5 | Home-page: https://bitbucket.org/pypa/distlib 6 | Author: Vinay Sajip 7 | Author-email: vinay_sajip@red-dove.com 8 | License: Python license 9 | Download-URL: https://bitbucket.org/pypa/distlib/downloads/distlib-0.3.1.zip 10 | Description: Low-level components of distutils2/packaging, augmented with higher-level APIs for making packaging easier. 11 | 12 | Platform: any 13 | Classifier: Development Status :: 5 - Production/Stable 14 | Classifier: Environment :: Console 15 | Classifier: Intended Audience :: Developers 16 | Classifier: License :: OSI Approved :: Python Software Foundation License 17 | Classifier: Operating System :: OS Independent 18 | Classifier: Programming Language :: Python 19 | Classifier: Programming Language :: Python :: 2 20 | Classifier: Programming Language :: Python :: 3 21 | Classifier: Programming Language :: Python :: 2.7 22 | Classifier: Programming Language :: Python :: 3.2 23 | Classifier: Programming Language :: Python :: 3.3 24 | Classifier: Programming Language :: Python :: 3.4 25 | Classifier: Programming Language :: Python :: 3.5 26 | Classifier: Programming Language :: Python :: 3.6 27 | Classifier: Programming Language :: Python :: 3.7 28 | Classifier: Programming Language :: Python :: 3.8 29 | Classifier: Topic :: Software Development 30 | Classifier: Topic :: Utilities 31 | -------------------------------------------------------------------------------- /pkg/python/packaging/testdata/distlib-0.3.1.METADATA: -------------------------------------------------------------------------------- 1 | Metadata-Version: 1.1 2 | Name: distlib 3 | Version: 0.3.1 4 | Summary: Distribution utilities 5 | Description: Low-level components of distutils2/packaging, augmented with higher-level APIs for making packaging easier. 6 | Home-page: https://bitbucket.org/pypa/distlib 7 | Author: Vinay Sajip 8 | Author-email: vinay_sajip@red-dove.com 9 | License: Python license 10 | Classifier: Development Status :: 5 - Production/Stable 11 | Classifier: Environment :: Console 12 | Classifier: Intended Audience :: Developers 13 | Classifier: License :: OSI Approved :: Python Software Foundation License 14 | Classifier: Operating System :: OS Independent 15 | Classifier: Programming Language :: Python 16 | Classifier: Programming Language :: Python :: 2 17 | Classifier: Programming Language :: Python :: 3 18 | Classifier: Programming Language :: Python :: 2.7 19 | Classifier: Programming Language :: Python :: 3.5 20 | Classifier: Programming Language :: Python :: 3.6 21 | Classifier: Programming Language :: Python :: 3.7 22 | Classifier: Programming Language :: Python :: 3.8 23 | Classifier: Topic :: Software Development :: Libraries :: Python Modules 24 | Download-URL: https://bitbucket.org/pypa/distlib/downloads/distlib-0.3.1.zip 25 | -------------------------------------------------------------------------------- /pkg/python/packaging/testdata/invalid.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /pkg/python/packaging/testdata/simple-0.1.0.METADATA: -------------------------------------------------------------------------------- 1 | Metadata-Version: 2.1 2 | Name: simple 3 | Version: 0.1.0 4 | -------------------------------------------------------------------------------- /pkg/python/packaging/testdata/unidecode-egg-info.PKG-INFO: -------------------------------------------------------------------------------- 1 | Metadata-Version: 1.1 2 | Name: Unidecode 3 | Version: 0.4.1 4 | Summary: US-ASCII transliterations of Unicode text 5 | Home-page: http://www.tablix.org/~avian/blog/archives/2009/01/unicode_transliteration_in_python/ 6 | Author: Tomaz Solc 7 | Author-email: tomaz.solc@tablix.org 8 | License: UNKNOWN 9 | Description: 10 | Unidecode 11 | ========= 12 | 13 | ASCII transliterations of Unicode text 14 | 15 | Example Use 16 | ----------- 17 | 18 | :: 19 | 20 | from unidecode import unidecode 21 | print unidecode(u"北亰") 22 | 23 | # That prints: Bei Jing 24 | 25 | Description 26 | ----------- 27 | 28 | It often happens that you have non-Roman text data in Unicode, but 29 | you can't display it -- usually because you're trying to show it 30 | to a user via an application that doesn't support Unicode, or 31 | because the fonts you need aren't accessible. You could represent 32 | the Unicode characters as "???????" or " BA A0q0...", but 33 | that's nearly useless to the user who actually wants to read what 34 | the text says. 35 | 36 | What Unidecode provides is a function, 'unidecode(...)' that 37 | takes Unicode data and tries to represent it in ASCII characters 38 | (i.e., the universally displayable characters between 0x00 and 0x7F). 39 | The representation is almost always an attempt at *transliteration* 40 | -- i.e., conveying, in Roman letters, the pronunciation expressed by 41 | the text in some other writing system. (See the example above) 42 | 43 | This is a Python port of Text::Unidecode Perl module by 44 | Sean M. Burke . 45 | 46 | Platform: UNKNOWN 47 | Provides: unidecode 48 | -------------------------------------------------------------------------------- /pkg/python/pip/parse_test.go: -------------------------------------------------------------------------------- 1 | package pip 2 | 3 | import ( 4 | "os" 5 | "path" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | "github.com/stretchr/testify/require" 10 | 11 | "github.com/aquasecurity/go-dep-parser/pkg/types" 12 | ) 13 | 14 | func TestParse(t *testing.T) { 15 | vectors := []struct { 16 | file string 17 | want []types.Library 18 | }{ 19 | { 20 | file: "testdata/requirements_flask.txt", 21 | want: requirementsFlask, 22 | }, 23 | { 24 | file: "testdata/requirements_comments.txt", 25 | want: requirementsComments, 26 | }, 27 | { 28 | file: "testdata/requirements_spaces.txt", 29 | want: requirementsSpaces, 30 | }, 31 | { 32 | file: "testdata/requirements_no_version.txt", 33 | want: requirementsNoVersion, 34 | }, 35 | { 36 | file: "testdata/requirements_operator.txt", 37 | want: requirementsOperator, 38 | }, 39 | { 40 | file: "testdata/requirements_hash.txt", 41 | want: requirementsHash, 42 | }, 43 | { 44 | file: "testdata/requirements_hyphens.txt", 45 | want: requirementsHyphens, 46 | }, 47 | { 48 | file: "testdata/requirement_exstras.txt", 49 | want: requirementsExtras, 50 | }, 51 | { 52 | file: "testdata/requirements_utf16le.txt", 53 | want: requirementsUtf16le, 54 | }, 55 | } 56 | 57 | for _, v := range vectors { 58 | t.Run(path.Base(v.file), func(t *testing.T) { 59 | f, err := os.Open(v.file) 60 | require.NoError(t, err) 61 | 62 | got, _, err := NewParser().Parse(f) 63 | require.NoError(t, err) 64 | 65 | assert.Equal(t, v.want, got) 66 | }) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /pkg/python/pip/parse_testcase.go: -------------------------------------------------------------------------------- 1 | package pip 2 | 3 | import "github.com/aquasecurity/go-dep-parser/pkg/types" 4 | 5 | var ( 6 | requirementsFlask = []types.Library{ 7 | {Name: "click", Version: "8.0.0"}, 8 | {Name: "Flask", Version: "2.0.0"}, 9 | {Name: "itsdangerous", Version: "2.0.0"}, 10 | {Name: "Jinja2", Version: "3.0.0"}, 11 | {Name: "MarkupSafe", Version: "2.0.0"}, 12 | {Name: "Werkzeug", Version: "2.0.0"}, 13 | } 14 | 15 | requirementsComments = []types.Library{ 16 | {Name: "click", Version: "8.0.0"}, 17 | {Name: "Flask", Version: "2.0.0"}, 18 | {Name: "Jinja2", Version: "3.0.0"}, 19 | {Name: "MarkupSafe", Version: "2.0.0"}, 20 | } 21 | 22 | requirementsSpaces = []types.Library{ 23 | {Name: "click", Version: "8.0.0"}, 24 | {Name: "Flask", Version: "2.0.0"}, 25 | {Name: "itsdangerous", Version: "2.0.0"}, 26 | {Name: "Jinja2", Version: "3.0.0"}, 27 | } 28 | 29 | requirementsNoVersion = []types.Library{ 30 | {Name: "Flask", Version: "2.0.0"}, 31 | } 32 | 33 | requirementsOperator = []types.Library{ 34 | {Name: "Django", Version: "2.3.4"}, 35 | {Name: "SomeProject", Version: "5.4"}, 36 | } 37 | 38 | requirementsHash = []types.Library{ 39 | {Name: "FooProject", Version: "1.2"}, 40 | {Name: "Jinja2", Version: "3.0.0"}, 41 | } 42 | 43 | requirementsHyphens = []types.Library{ 44 | {Name: "oauth2-client", Version: "4.0.0"}, 45 | {Name: "python-gitlab", Version: "2.0.0"}, 46 | } 47 | 48 | requirementsExtras = []types.Library{ 49 | {Name: "pyjwt", Version: "2.1.0"}, 50 | {Name: "celery", Version: "4.4.7"}, 51 | } 52 | 53 | requirementsUtf16le = []types.Library{ 54 | {Name: "attrs", Version: "20.3.0"}, 55 | } 56 | ) 57 | -------------------------------------------------------------------------------- /pkg/python/pip/testdata/requirement_exstras.txt: -------------------------------------------------------------------------------- 1 | pyjwt[crypto]==2.1.0 2 | celery[redis, pytest]==4.4.7 -------------------------------------------------------------------------------- /pkg/python/pip/testdata/requirements_comments.txt: -------------------------------------------------------------------------------- 1 | # foo==8.0.0 2 | #bar==8.0.0 3 | #comment 4 | click==8.0.0 5 | Flask==2.0.0 #comment 6 | Jinja2==3.0.0#comment 7 | MarkupSafe==2.0.0 # comment 8 | 9 | -------------------------------------------------------------------------------- /pkg/python/pip/testdata/requirements_flask.txt: -------------------------------------------------------------------------------- 1 | click==8.0.0 2 | Flask==2.0.0 3 | itsdangerous==2.0.0 4 | Jinja2==3.0.0 5 | MarkupSafe==2.0.0 6 | Werkzeug==2.0.0 7 | -------------------------------------------------------------------------------- /pkg/python/pip/testdata/requirements_hash.txt: -------------------------------------------------------------------------------- 1 | FooProject == 1.2 --hash=sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 \ 2 | --hash=sha256:486ea46224d1bb4fb680f34f7c9ad96a8f24ec88be73ea8e5a6c65260e9cb8a7 3 | 4 | Jinja2 == 3.0.0 \ 5 | --hash=sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 \ 6 | --hash=sha256:486ea46224d1bb4fb680f34f7c9ad96a8f24ec88be73ea8e5a6c65260e9cb8a7 -------------------------------------------------------------------------------- /pkg/python/pip/testdata/requirements_hyphens.txt: -------------------------------------------------------------------------------- 1 | oauth2-client==4.0.0 2 | python-gitlab==2.0.0 -------------------------------------------------------------------------------- /pkg/python/pip/testdata/requirements_no_version.txt: -------------------------------------------------------------------------------- 1 | Flask==2.0.0 2 | pandas 3 | -------------------------------------------------------------------------------- /pkg/python/pip/testdata/requirements_operator.txt: -------------------------------------------------------------------------------- 1 | keyring >= 4.1.1 # Minimum version 4.1.1 2 | coverage != 3.5 # Version Exclusion. Anything except version 3.5 3 | Mopidy-Dirble ~= 1.1 # Compatible release. Same as >= 1.1, == 1.* 4 | Django == 2.3.4 5 | SomeProject ==5.4 ; python_version < '3.8' 6 | numpyNew; sys_platform == 'win32' 7 | numpy >= 3.4.1; sys_platform == 'win32' -------------------------------------------------------------------------------- /pkg/python/pip/testdata/requirements_spaces.txt: -------------------------------------------------------------------------------- 1 | click == 8.0.0 2 | Flask ==2.0.0 3 | itsdangerous== 2.0.0 4 | 5 | Jinja2 == 3.0.0 # comment 6 | -------------------------------------------------------------------------------- /pkg/python/pip/testdata/requirements_utf16le.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/go-dep-parser/1de9a375c6295ae769042b9cde998be6c0065a5d/pkg/python/pip/testdata/requirements_utf16le.txt -------------------------------------------------------------------------------- /pkg/python/pipenv/parse.go: -------------------------------------------------------------------------------- 1 | package pipenv 2 | 3 | import ( 4 | "github.com/liamg/jfather" 5 | "io" 6 | "strings" 7 | 8 | dio "github.com/aquasecurity/go-dep-parser/pkg/io" 9 | "github.com/aquasecurity/go-dep-parser/pkg/types" 10 | "golang.org/x/xerrors" 11 | ) 12 | 13 | type lockFile struct { 14 | Default map[string]dependency `json:"default"` 15 | } 16 | type dependency struct { 17 | Version string `json:"version"` 18 | StartLine int 19 | EndLine int 20 | } 21 | 22 | type Parser struct{} 23 | 24 | func NewParser() types.Parser { 25 | return &Parser{} 26 | } 27 | 28 | func (p *Parser) Parse(r dio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { 29 | var lockFile lockFile 30 | input, err := io.ReadAll(r) 31 | if err != nil { 32 | return nil, nil, xerrors.Errorf("failed to read packages.lock.json: %w", err) 33 | } 34 | if err := jfather.Unmarshal(input, &lockFile); err != nil { 35 | return nil, nil, xerrors.Errorf("failed to decode Pipenv.lock: %w", err) 36 | } 37 | 38 | var libs []types.Library 39 | for pkgName, dependency := range lockFile.Default { 40 | libs = append(libs, types.Library{ 41 | Name: pkgName, 42 | Version: strings.TrimLeft(dependency.Version, "="), 43 | Locations: []types.Location{{StartLine: dependency.StartLine, EndLine: dependency.EndLine}}, 44 | }) 45 | } 46 | return libs, nil, nil 47 | } 48 | 49 | // UnmarshalJSONWithMetadata needed to detect start and end lines of deps 50 | func (t *dependency) UnmarshalJSONWithMetadata(node jfather.Node) error { 51 | if err := node.Decode(&t); err != nil { 52 | return err 53 | } 54 | // Decode func will overwrite line numbers if we save them first 55 | t.StartLine = node.Range().Start.Line 56 | t.EndLine = node.Range().End.Line 57 | return nil 58 | } 59 | -------------------------------------------------------------------------------- /pkg/python/pipenv/parse_test.go: -------------------------------------------------------------------------------- 1 | package pipenv 2 | 3 | import ( 4 | "os" 5 | "path" 6 | "sort" 7 | "strings" 8 | "testing" 9 | 10 | "github.com/stretchr/testify/assert" 11 | "github.com/stretchr/testify/require" 12 | 13 | "github.com/aquasecurity/go-dep-parser/pkg/types" 14 | ) 15 | 16 | func TestParse(t *testing.T) { 17 | vectors := []struct { 18 | file string // Test input file 19 | want []types.Library 20 | }{ 21 | { 22 | file: "testdata/Pipfile_normal.lock", 23 | want: pipenvNormal, 24 | }, 25 | { 26 | file: "testdata/Pipfile_django.lock", 27 | want: pipenvDjango, 28 | }, 29 | { 30 | file: "testdata/Pipfile_many.lock", 31 | want: pipenvMany, 32 | }, 33 | } 34 | 35 | for _, v := range vectors { 36 | t.Run(path.Base(v.file), func(t *testing.T) { 37 | f, err := os.Open(v.file) 38 | require.NoError(t, err) 39 | 40 | got, _, err := NewParser().Parse(f) 41 | require.NoError(t, err) 42 | 43 | sort.Slice(got, func(i, j int) bool { 44 | ret := strings.Compare(got[i].Name, got[j].Name) 45 | if ret == 0 { 46 | return got[i].Version < got[j].Version 47 | } 48 | return ret < 0 49 | }) 50 | 51 | sort.Slice(v.want, func(i, j int) bool { 52 | ret := strings.Compare(v.want[i].Name, v.want[j].Name) 53 | if ret == 0 { 54 | return v.want[i].Version < v.want[j].Version 55 | } 56 | return ret < 0 57 | }) 58 | 59 | assert.Equal(t, v.want, got) 60 | }) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /pkg/python/poetry/testdata/poetry_normal.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "pypi" 5 | version = "2.1" 6 | description = "PyPI is the Python Package Index at http://pypi.org/" 7 | category = "main" 8 | optional = false 9 | python-versions = "*" 10 | files = [ 11 | {file = "pypi-2.1.tar.gz", hash = "sha256:f014c87f871c2143ff613d9d13a59cc8ab8309b048754c27da8c58b21de2c10d"}, 12 | ] 13 | 14 | [metadata] 15 | lock-version = "2.0" 16 | python-versions = "^3.9" 17 | content-hash = "8fe1a16a0f2018499bedde14bd5c44aa7d9540b90c1fe0d53610a62f22e4f612" 18 | -------------------------------------------------------------------------------- /pkg/python/pyproject/pyproject.go: -------------------------------------------------------------------------------- 1 | package pyproject 2 | 3 | import ( 4 | "io" 5 | 6 | "github.com/BurntSushi/toml" 7 | "golang.org/x/xerrors" 8 | ) 9 | 10 | type PyProject struct { 11 | Tool Tool `toml:"tool"` 12 | } 13 | 14 | type Tool struct { 15 | Poetry Poetry `toml:"poetry"` 16 | } 17 | 18 | type Poetry struct { 19 | Dependencies map[string]interface{} `toml:"dependencies"` 20 | } 21 | 22 | // Parser parses pyproject.toml defined in PEP518. 23 | // https://peps.python.org/pep-0518/ 24 | type Parser struct { 25 | } 26 | 27 | func NewParser() *Parser { 28 | return &Parser{} 29 | } 30 | 31 | func (p *Parser) Parse(r io.Reader) (map[string]interface{}, error) { 32 | var conf PyProject 33 | if _, err := toml.NewDecoder(r).Decode(&conf); err != nil { 34 | return nil, xerrors.Errorf("toml decode error: %w", err) 35 | } 36 | return conf.Tool.Poetry.Dependencies, nil 37 | } 38 | -------------------------------------------------------------------------------- /pkg/python/pyproject/pyproject_test.go: -------------------------------------------------------------------------------- 1 | package pyproject_test 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | "github.com/stretchr/testify/require" 10 | 11 | "github.com/aquasecurity/go-dep-parser/pkg/python/pyproject" 12 | ) 13 | 14 | func TestParser_Parse(t *testing.T) { 15 | tests := []struct { 16 | name string 17 | file string 18 | want map[string]interface{} 19 | wantErr assert.ErrorAssertionFunc 20 | }{ 21 | { 22 | name: "happy path", 23 | file: "testdata/happy.toml", 24 | want: map[string]interface{}{ 25 | "flask": "^1.0", 26 | "python": "^3.9", 27 | "requests": map[string]interface{}{ 28 | "version": "2.28.1", 29 | "optional": true, 30 | }, 31 | "virtualenv": []interface{}{ 32 | map[string]interface{}{ 33 | "version": "^20.4.3,!=20.4.5,!=20.4.6", 34 | }, 35 | map[string]interface{}{ 36 | "version": "<20.16.6", 37 | "markers": "sys_platform == 'win32' and python_version == '3.9'", 38 | }, 39 | }, 40 | }, 41 | wantErr: assert.NoError, 42 | }, 43 | { 44 | name: "sad path", 45 | file: "testdata/sad.toml", 46 | wantErr: assert.Error, 47 | }, 48 | } 49 | for _, tt := range tests { 50 | t.Run(tt.name, func(t *testing.T) { 51 | f, err := os.Open(tt.file) 52 | require.NoError(t, err) 53 | defer f.Close() 54 | 55 | p := &pyproject.Parser{} 56 | got, err := p.Parse(f) 57 | if !tt.wantErr(t, err, fmt.Sprintf("Parse(%v)", tt.file)) { 58 | return 59 | } 60 | assert.Equalf(t, tt.want, got, "Parse(%v)", tt.file) 61 | }) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /pkg/python/pyproject/testdata/happy.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "example" 3 | version = "0.1.0" 4 | description = "My Hello World Example" 5 | 6 | [tool.poetry.dependencies] 7 | python = "^3.9" 8 | flask = "^1.0" 9 | requests = {version = "2.28.1", optional = true} 10 | virtualenv = [ 11 | { version = "^20.4.3,!=20.4.5,!=20.4.6" }, 12 | { version = "<20.16.6", markers = "sys_platform == 'win32' and python_version == '3.9'" }, 13 | ] 14 | 15 | [tool.poetry.dev-dependencies] 16 | 17 | [build-system] 18 | requires = ["poetry-core>=1.0.0"] 19 | build-backend = "poetry.core.masonry.api" 20 | -------------------------------------------------------------------------------- /pkg/python/pyproject/testdata/sad.toml: -------------------------------------------------------------------------------- 1 | [ -------------------------------------------------------------------------------- /pkg/ruby/bundler/testdata/Gemfile_bundler2.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | coderay (1.1.3) 5 | concurrent-ruby (1.1.10) 6 | dotenv (2.7.6) 7 | faker (2.21.0) 8 | i18n (>= 1.8.11, < 2) 9 | i18n (1.10.0) 10 | concurrent-ruby (~> 1.0) 11 | json (2.6.2) 12 | method_source (1.0.0) 13 | pry (0.14.1) 14 | coderay (~> 1.1) 15 | method_source (~> 1.0) 16 | 17 | PLATFORMS 18 | x86_64-linux 19 | 20 | DEPENDENCIES 21 | dotenv (~> 2.7) 22 | faker (~> 2.21) 23 | json (~> 2.6) 24 | pry (~> 0.14.1) 25 | 26 | BUNDLED WITH 27 | 2.3.7 -------------------------------------------------------------------------------- /pkg/ruby/bundler/testdata/Gemfile_malformed.lock: -------------------------------------------------------------------------------- 1 | malformed -------------------------------------------------------------------------------- /pkg/ruby/bundler/testdata/Gemfile_normal.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | coderay (1.1.2) 5 | concurrent-ruby (1.1.5) 6 | dotenv (2.7.2) 7 | faker (1.9.3) 8 | i18n (>= 0.7) 9 | i18n (1.6.0) 10 | concurrent-ruby (~> 1.0) 11 | method_source (0.9.2) 12 | pry (0.12.2) 13 | coderay (~> 1.1.0) 14 | method_source (~> 0.9.0) 15 | 16 | PLATFORMS 17 | ruby 18 | 19 | DEPENDENCIES 20 | dotenv (~> 2.7) 21 | faker (~> 1.9) 22 | pry (~> 0.12.2) 23 | 24 | BUNDLED WITH 25 | 1.17.2 26 | -------------------------------------------------------------------------------- /pkg/ruby/gemspec/parse_test.go: -------------------------------------------------------------------------------- 1 | package gemspec_test 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/stretchr/testify/require" 9 | 10 | "github.com/aquasecurity/go-dep-parser/pkg/ruby/gemspec" 11 | "github.com/aquasecurity/go-dep-parser/pkg/types" 12 | ) 13 | 14 | func TestParse(t *testing.T) { 15 | tests := []struct { 16 | name string 17 | inputFile string 18 | want []types.Library 19 | wantErr string 20 | }{ 21 | { 22 | name: "happy", 23 | inputFile: "testdata/normal00.gemspec", 24 | want: []types.Library{{ 25 | Name: "rake", 26 | Version: "13.0.3", 27 | License: "MIT", 28 | }}, 29 | }, 30 | { 31 | name: "another variable name", 32 | inputFile: "testdata/normal01.gemspec", 33 | want: []types.Library{{ 34 | Name: "async", 35 | Version: "1.25.0", 36 | }}, 37 | }, 38 | { 39 | name: "license", 40 | inputFile: "testdata/license.gemspec", 41 | want: []types.Library{{ 42 | Name: "async", 43 | Version: "1.25.0", 44 | License: "MIT", 45 | }}, 46 | }, 47 | { 48 | name: "multiple licenses", 49 | inputFile: "testdata/multiple_licenses.gemspec", 50 | want: []types.Library{{ 51 | Name: "test-unit", 52 | Version: "3.3.7", 53 | License: "Ruby, BSDL, PSFL", 54 | }}, 55 | }, 56 | { 57 | name: "malformed variable name", 58 | inputFile: "testdata/malformed00.gemspec", 59 | wantErr: "failed to parse gemspec", 60 | }, 61 | { 62 | name: "missing version", 63 | inputFile: "testdata/malformed01.gemspec", 64 | wantErr: "failed to parse gemspec", 65 | }, 66 | } 67 | for _, tt := range tests { 68 | t.Run(tt.name, func(t *testing.T) { 69 | f, err := os.Open(tt.inputFile) 70 | require.NoError(t, err) 71 | 72 | got, _, err := gemspec.NewParser().Parse(f) 73 | if tt.wantErr != "" { 74 | require.NotNil(t, err) 75 | assert.Contains(t, err.Error(), tt.wantErr) 76 | return 77 | } 78 | assert.Equal(t, tt.want, got) 79 | }) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /pkg/ruby/gemspec/testdata/license.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | # ... REDACTED ... 3 | 4 | Gem::Specification.new do |spec| 5 | spec.name = "async".freeze 6 | spec.version = "1.25.0" 7 | spec.license = "MIT" 8 | 9 | # ... REDACTED ... 10 | end 11 | -------------------------------------------------------------------------------- /pkg/ruby/gemspec/testdata/malformed00.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | # ... REDACTED ... 3 | 4 | # Wrong attribute value assignment. 5 | Gem::Specification.new do |spec| 6 | s.name = "async".freeze 7 | s.version = "1.25.0" 8 | 9 | # ... REDACTED ... 10 | end 11 | -------------------------------------------------------------------------------- /pkg/ruby/gemspec/testdata/malformed01.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | # ... REDACTED ... 3 | 4 | # Missing version attribute. 5 | 6 | Gem::Specification.new do |s| 7 | s.name = "async".freeze 8 | 9 | # ... REDACTED ... 10 | end 11 | -------------------------------------------------------------------------------- /pkg/ruby/gemspec/testdata/multiple_licenses.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | # stub: test-unit 3.3.7 ruby lib 3 | 4 | Gem::Specification.new do |s| 5 | s.name = "test-unit".freeze 6 | s.version = "3.3.7" 7 | 8 | s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= 9 | s.metadata = { "source_code_uri" => "https://github.com/test-unit/test-unit" } if s.respond_to? :metadata= 10 | s.require_paths = ["lib".freeze] 11 | s.authors = ["Kouhei Sutou".freeze, "Haruka Yoshihara".freeze] 12 | s.date = "2020-11-18" 13 | s.description = "test-unit (Test::Unit) is unit testing framework for Ruby, based on xUnit\nprinciples. These were originally designed by Kent Beck, creator of extreme\nprogramming software development methodology, for Smalltalk's SUnit. It allows\nwriting tests, checking results and automated testing in Ruby.\n".freeze 14 | s.email = ["kou@cozmixng.org".freeze, "yoshihara@clear-code.com".freeze] 15 | s.homepage = "http://test-unit.github.io/".freeze 16 | s.licenses = ["Ruby".freeze,"BSDL".freeze, "PSFL".freeze] 17 | s.rubygems_version = "3.2.22".freeze 18 | s.summary = "An xUnit family unit testing framework for Ruby.".freeze 19 | 20 | s.installed_by_version = "3.2.22" if s.respond_to? :installed_by_version 21 | 22 | if s.respond_to? :specification_version then 23 | s.specification_version = 4 24 | end 25 | 26 | if s.respond_to? :add_runtime_dependency then 27 | s.add_runtime_dependency(%q.freeze, [">= 0"]) 28 | s.add_development_dependency(%q.freeze, [">= 0"]) 29 | s.add_development_dependency(%q.freeze, [">= 0"]) 30 | s.add_development_dependency(%q.freeze, [">= 0"]) 31 | s.add_development_dependency(%q.freeze, [">= 0"]) 32 | s.add_development_dependency(%q.freeze, [">= 0"]) 33 | else 34 | s.add_dependency(%q.freeze, [">= 0"]) 35 | s.add_dependency(%q.freeze, [">= 0"]) 36 | s.add_dependency(%q.freeze, [">= 0"]) 37 | s.add_dependency(%q.freeze, [">= 0"]) 38 | s.add_dependency(%q.freeze, [">= 0"]) 39 | s.add_dependency(%q.freeze, [">= 0"]) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /pkg/ruby/gemspec/testdata/normal00.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | # stub: rake 13.0.3 ruby lib 3 | 4 | Gem::Specification.new do |s| 5 | s.name = "rake".freeze 6 | s.version = "13.0.3" 7 | 8 | s.required_rubygems_version = Gem::Requirement.new(">= 1.3.2".freeze) if s.respond_to? :required_rubygems_version= 9 | s.metadata = { "bug_tracker_uri" => "https://github.com/ruby/rake/issues", "changelog_uri" => "https://github.com/ruby/rake/blob/v13.0.3/History.rdoc", "documentation_uri" => "https://ruby.github.io/rake", "source_code_uri" => "https://github.com/ruby/rake/tree/v13.0.3" } if s.respond_to? :metadata= 10 | s.require_paths = ["lib".freeze] 11 | s.authors = ["Hiroshi SHIBATA".freeze, "Eric Hodel".freeze, "Jim Weirich".freeze] 12 | s.bindir = "exe".freeze 13 | s.date = "2020-12-21" 14 | s.description = "Rake is a Make-like program implemented in Ruby. Tasks and dependencies are\nspecified in standard Ruby syntax.\nRake has the following features:\n * Rakefiles (rake's version of Makefiles) are completely defined in standard Ruby syntax.\n No XML files to edit. No quirky Makefile syntax to worry about (is that a tab or a space?)\n * Users can specify tasks with prerequisites.\n * Rake supports rule patterns to synthesize implicit tasks.\n * Flexible FileLists that act like arrays but know about manipulating file names and paths.\n * Supports parallel execution of tasks.\n".freeze 15 | s.email = ["hsbt@ruby-lang.org".freeze, "drbrain@segment7.net".freeze, "".freeze] 16 | s.executables = ["rake".freeze] 17 | s.files = ["exe/rake".freeze] 18 | s.homepage = "https://github.com/ruby/rake".freeze 19 | s.licenses = ["MIT".freeze] 20 | s.rdoc_options = ["--main".freeze, "README.rdoc".freeze] 21 | s.required_ruby_version = Gem::Requirement.new(">= 2.2".freeze) 22 | s.rubygems_version = "3.2.22".freeze 23 | s.summary = "Rake is a Make-like program implemented in Ruby".freeze 24 | 25 | s.installed_by_version = "3.2.22" if s.respond_to? :installed_by_version 26 | end 27 | -------------------------------------------------------------------------------- /pkg/ruby/gemspec/testdata/normal01.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | # ... REDACTED ... 3 | 4 | Gem::Specification.new do |spec| 5 | spec.name = "async".freeze # comment 6 | spec.version = "1.25.0" 7 | spec.licenses = "MIT" # invalid 8 | 9 | # ... REDACTED ... 10 | end 11 | -------------------------------------------------------------------------------- /pkg/rust/binary/testdata/dummy: -------------------------------------------------------------------------------- 1 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -------------------------------------------------------------------------------- /pkg/rust/binary/testdata/test.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/go-dep-parser/1de9a375c6295ae769042b9cde998be6c0065a5d/pkg/rust/binary/testdata/test.elf -------------------------------------------------------------------------------- /pkg/rust/binary/testdata/test.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/go-dep-parser/1de9a375c6295ae769042b9cde998be6c0065a5d/pkg/rust/binary/testdata/test.exe -------------------------------------------------------------------------------- /pkg/rust/binary/testdata/test.macho: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aquasecurity/go-dep-parser/1de9a375c6295ae769042b9cde998be6c0065a5d/pkg/rust/binary/testdata/test.macho -------------------------------------------------------------------------------- /pkg/rust/cargo/naive_pkg_parser.go: -------------------------------------------------------------------------------- 1 | package cargo 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "io" 7 | "strings" 8 | 9 | "github.com/aquasecurity/go-dep-parser/pkg/utils" 10 | ) 11 | 12 | type pkgPosition struct { 13 | start int 14 | end int 15 | } 16 | type minPkg struct { 17 | name string 18 | version string 19 | position pkgPosition 20 | } 21 | 22 | func (pkg *minPkg) setEndPositionIfEmpty(n int) { 23 | if pkg.position.end == 0 { 24 | pkg.position.end = n 25 | } 26 | } 27 | 28 | type naivePkgParser struct { 29 | r io.Reader 30 | } 31 | 32 | func (parser *naivePkgParser) parse() map[string]pkgPosition { 33 | var currentPkg minPkg = minPkg{} 34 | var idx = make(map[string]pkgPosition, 0) 35 | 36 | scanner := bufio.NewScanner(parser.r) 37 | lineNum := 1 38 | for scanner.Scan() { 39 | line := scanner.Text() 40 | if strings.HasPrefix(strings.TrimSpace(line), "[") { 41 | if currentPkg.name != "" { 42 | pkgId := utils.PackageID(currentPkg.name, currentPkg.version) 43 | currentPkg.setEndPositionIfEmpty(lineNum - 1) 44 | idx[pkgId] = currentPkg.position 45 | } 46 | currentPkg = minPkg{} 47 | currentPkg.position.start = lineNum 48 | 49 | } else if strings.HasPrefix(strings.TrimSpace(line), "name =") { 50 | currentPkg.name = propertyValue(line) 51 | } else if strings.HasPrefix(strings.TrimSpace(line), "version =") { 52 | currentPkg.version = propertyValue(line) 53 | } else if strings.TrimSpace(line) == "" { 54 | currentPkg.setEndPositionIfEmpty(lineNum - 1) 55 | } 56 | 57 | lineNum++ 58 | } 59 | // add last item 60 | if currentPkg.name != "" { 61 | pkgId := fmt.Sprintf("%s@%s", currentPkg.name, currentPkg.version) 62 | currentPkg.setEndPositionIfEmpty(lineNum - 1) 63 | idx[pkgId] = currentPkg.position 64 | } 65 | return idx 66 | } 67 | func propertyValue(line string) string { 68 | parts := strings.Split(line, "=") 69 | if len(parts) == 2 { 70 | return strings.Trim(parts[1], ` "`) 71 | } 72 | return "" 73 | } 74 | -------------------------------------------------------------------------------- /pkg/rust/cargo/testdata/cargo_invalid.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "libc" 5 | version = "0.2.54" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | 8 | [[package]] 9 | name = "normal" 10 | version = 11 | dependencies = [ 12 | "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", 13 | ] 14 | 15 | [[package]] 16 | name = "typemap" 17 | version = "0.3.3" 18 | source = "registry+https://github.com/rust-lang/crates.io-index" 19 | dependencies = [ 20 | "unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 21 | ] 22 | 23 | [[package]] 24 | name = "url" 25 | version = "1.7.2" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | dependencies = [ 28 | "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 29 | "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", 30 | "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 31 | ] 32 | 33 | [metadata] 34 | "checksum libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)" = "c6785aa7dd976f5fbf3b71cfd9cd49d7f783c1ff565a858d71031c6c313aa5c6" 35 | -------------------------------------------------------------------------------- /pkg/rust/cargo/testdata/cargo_mixed.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "libc" 5 | version = "0.2.54" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | 8 | 9 | [[package]] 10 | name = "unsafe-any" 11 | version = "0.4.2" 12 | source = "registry+https://github.com/rust-lang/crates.io-index" 13 | 14 | 15 | 16 | 17 | [[package]] 18 | name = "normal" 19 | version = "0.1.0" 20 | dependencies = [ 21 | "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", 22 | ] 23 | 24 | # Extra comments 25 | 26 | [[package]] 27 | name = "url" 28 | version = """1.7.2""" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | dependencies = [ 31 | "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 32 | "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", 33 | "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 34 | ] 35 | 36 | [[package]] 37 | name = "idna" 38 | version = "0.1.5" 39 | source = "registry+https://github.com/rust-lang/crates.io-index" 40 | 41 | [[package]] 42 | name = "matches" 43 | version = "0.1.8" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | 46 | [[package]] 47 | name = "percent-encoding" 48 | version = "1.0.1" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | 51 | 52 | [metadata] 53 | "checksum libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)" = "c6785aa7dd976f5fbf3b71cfd9cd49d7f783c1ff565a858d71031c6c313aa5c6" 54 | 55 | [[package]] 56 | name = "typemap" 57 | version = "0.3.3" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | dependencies = [ 60 | "unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 61 | ] 62 | -------------------------------------------------------------------------------- /pkg/rust/cargo/testdata/cargo_normal.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "libc" 5 | version = "0.2.54" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | 8 | [[package]] 9 | name = "normal" 10 | version = "0.1.0" 11 | dependencies = [ 12 | "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", 13 | ] 14 | 15 | [[package]] 16 | name = "unsafe-any" 17 | version = "0.4.2" 18 | source = "registry+https://github.com/rust-lang/crates.io-index" 19 | 20 | [[package]] 21 | name = "typemap" 22 | version = "0.3.3" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | dependencies = [ 25 | "unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 26 | ] 27 | 28 | [[package]] 29 | name = "idna" 30 | version = "0.1.5" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | 33 | [[package]] 34 | name = "matches" 35 | version = "0.1.8" 36 | source = "registry+https://github.com/rust-lang/crates.io-index" 37 | 38 | [[package]] 39 | name = "percent-encoding" 40 | version = "1.0.1" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | 43 | [[package]] 44 | name = "url" 45 | version = "1.7.2" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | dependencies = [ 48 | "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 49 | "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", 50 | "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 51 | ] 52 | 53 | [metadata] 54 | "checksum libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)" = "c6785aa7dd976f5fbf3b71cfd9cd49d7f783c1ff565a858d71031c6c313aa5c6" 55 | -------------------------------------------------------------------------------- /pkg/swift/cocoapods/testdata/empty.lock: -------------------------------------------------------------------------------- 1 | COCOAPODS: 1.11.2 -------------------------------------------------------------------------------- /pkg/swift/cocoapods/testdata/happy.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - AppCenter (4.2.0): 3 | - AppCenter/Analytics (= 4.2.0) 4 | - AppCenter/Crashes (= 4.2.0) 5 | - AppCenter/Analytics (4.2.0): 6 | - AppCenter/Core 7 | - AppCenter/Core (4.2.0) 8 | - AppCenter/Crashes (4.2.0): 9 | - AppCenter/Core 10 | - KeychainAccess (4.2.1) 11 | 12 | COCOAPODS: 1.11.2 -------------------------------------------------------------------------------- /pkg/swift/cocoapods/testdata/sad.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - AppCenter = 4.2.0 3 | 4 | COCOAPODS: 1.11.2 -------------------------------------------------------------------------------- /pkg/swift/swift/testdata/empty-Package.resolved: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /pkg/swift/swift/testdata/happy-v1-Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "Nimble", 6 | "repositoryURL": "https://github.com/Quick/Nimble.git", 7 | "state": { 8 | "branch": null, 9 | "revision": "c93f16c25af5770f0d3e6af27c9634640946b068", 10 | "version": "9.2.1" 11 | } 12 | }, 13 | { 14 | "package": "ReactiveSwift", 15 | "repositoryURL": "https://github.com/ReactiveCocoa/ReactiveSwift", 16 | "state": { 17 | "branch": null, 18 | "revision": "40c465af19b993344e84355c00669ba2022ca3cd", 19 | "version": "7.1.1" 20 | } 21 | } 22 | ] 23 | }, 24 | "version": 1 25 | } -------------------------------------------------------------------------------- /pkg/swift/swift/testdata/happy-v2-Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "pins" : [ 3 | { 4 | "identity" : "cwlcatchexception", 5 | "kind" : "remoteSourceControl", 6 | "location" : "https://github.com/mattgallagher/CwlCatchException.git", 7 | "state" : { 8 | "revision" : "3b123999de19bf04905bc1dfdb76f817b0f2cc00", 9 | "version" : "2.1.2" 10 | } 11 | }, 12 | { 13 | "identity" : "cwlpreconditiontesting", 14 | "kind" : "remoteSourceControl", 15 | "location" : "https://github.com/mattgallagher/CwlPreconditionTesting.git", 16 | "state" : { 17 | "revision" : "a23ded2c91df9156628a6996ab4f347526f17b6b", 18 | "version" : "2.1.2" 19 | } 20 | }, 21 | { 22 | "identity" : "nimble", 23 | "kind" : "remoteSourceControl", 24 | "location" : "https://github.com/Quick/Nimble.git", 25 | "state" : { 26 | "revision" : "c93f16c25af5770f0d3e6af27c9634640946b068", 27 | "version" : "9.2.1" 28 | } 29 | }, 30 | { 31 | "identity" : "quick", 32 | "kind" : "remoteSourceControl", 33 | "location" : "https://github.com/Quick/Quick.git", 34 | "state" : { 35 | "revision" : "494eff9ad74a37047782b0d5d8d84c7ff49a60e4", 36 | "version" : "7.2.0" 37 | } 38 | }, 39 | { 40 | "identity" : "reactiveswift", 41 | "kind" : "remoteSourceControl", 42 | "location" : "https://github.com/ReactiveCocoa/ReactiveSwift", 43 | "state" : { 44 | "revision" : "40c465af19b993344e84355c00669ba2022ca3cd", 45 | "version" : "7.1.1" 46 | } 47 | } 48 | ], 49 | "version" : 2 50 | } 51 | -------------------------------------------------------------------------------- /pkg/swift/swift/types.go: -------------------------------------------------------------------------------- 1 | package swift 2 | 3 | type LockFile struct { 4 | Object Object `json:"object"` 5 | Pins []Pin `json:"pins"` 6 | Version int `json:"version"` 7 | } 8 | 9 | type Object struct { 10 | Pins []Pin `json:"pins"` 11 | } 12 | 13 | type Pin struct { 14 | Package string `json:"package"` 15 | RepositoryURL string `json:"repositoryURL"` // Package.revision v1 16 | Location string `json:"location"` // Package.revision v2 17 | State State `json:"state"` 18 | StartLine int 19 | EndLine int 20 | } 21 | 22 | type State struct { 23 | Branch any `json:"branch"` 24 | Revision string `json:"revision"` 25 | Version string `json:"version"` 26 | } 27 | -------------------------------------------------------------------------------- /pkg/utils/utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "sort" 6 | 7 | "github.com/aquasecurity/go-dep-parser/pkg/types" 8 | "golang.org/x/exp/maps" 9 | ) 10 | 11 | func UniqueStrings(ss []string) []string { 12 | var results []string 13 | uniq := map[string]struct{}{} 14 | for _, s := range ss { 15 | if _, ok := uniq[s]; ok { 16 | continue 17 | } 18 | results = append(results, s) 19 | uniq[s] = struct{}{} 20 | } 21 | return results 22 | } 23 | 24 | func UniqueLibraries(libs []types.Library) []types.Library { 25 | if len(libs) == 0 { 26 | return nil 27 | } 28 | unique := map[string]types.Library{} 29 | for _, lib := range libs { 30 | identifier := fmt.Sprintf("%s@%s", lib.Name, lib.Version) 31 | if l, ok := unique[identifier]; !ok { 32 | unique[identifier] = lib 33 | } else { 34 | // There are times when we get 2 same libraries as root and dev dependencies. 35 | // https://github.com/aquasecurity/trivy/issues/5532 36 | // In these cases, we need to mark the dependency as a root dependency. 37 | if !lib.Dev { 38 | l.Dev = lib.Dev 39 | unique[identifier] = l 40 | } 41 | 42 | if len(lib.Locations) > 0 { 43 | // merge locations 44 | l.Locations = append(l.Locations, lib.Locations...) 45 | sort.Sort(l.Locations) 46 | unique[identifier] = l 47 | } 48 | } 49 | } 50 | libSlice := maps.Values(unique) 51 | sort.Sort(types.Libraries(libSlice)) 52 | 53 | return libSlice 54 | } 55 | 56 | func MergeMaps(parent, child map[string]string) map[string]string { 57 | if parent == nil { 58 | return child 59 | } 60 | // Clone parent map to avoid shadow overwrite 61 | newParent := maps.Clone(parent) 62 | for k, v := range child { 63 | newParent[k] = v 64 | } 65 | return newParent 66 | } 67 | 68 | func PackageID(name, version string) string { 69 | return fmt.Sprintf("%s@%s", name, version) 70 | } 71 | --------------------------------------------------------------------------------