diff --git a/.github/workflows/add-to-core-project.yml b/.github/workflows/add-to-core-project.yml index 4d21cf446a6c..725aed3c16fc 100644 --- a/.github/workflows/add-to-core-project.yml +++ b/.github/workflows/add-to-core-project.yml @@ -10,7 +10,7 @@ jobs: name: Add issue to project runs-on: ubuntu-latest steps: - - uses: actions/add-to-project@v1.0.1 + - uses: actions/add-to-project@9bfe908f2eaa7ba10340b31e314148fcfe6a2458 # v1.0.1 with: project-url: https://github.com/orgs/dependabot/projects/5 github-token: ${{ secrets.ADD_TO_PROJECT_PAT }} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 8a027063b452..edf930256110 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -47,13 +47,13 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: submodules: recursive # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL (ruby) - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@a12c274149a487a5539a726cb05bc6d1b7e0b5f2 # v3.24.11 with: languages: ${{ matrix.language }} config: | @@ -63,7 +63,7 @@ jobs: if: matrix.language == 'ruby' - name: Initialize CodeQL (others) - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@a12c274149a487a5539a726cb05bc6d1b7e0b5f2 # v3.24.11 with: languages: ${{ matrix.language }} if: matrix.language != 'ruby' @@ -71,7 +71,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v3 + uses: github/codeql-action/autobuild@a12c274149a487a5539a726cb05bc6d1b7e0b5f2 # v3.24.11 # ℹī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -85,4 +85,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@a12c274149a487a5539a726cb05bc6d1b7e0b5f2 # v3.24.11 diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index b8607e077202..d968710134ba 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -17,6 +17,6 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: Codespell - uses: codespell-project/actions-codespell@v2 + uses: codespell-project/actions-codespell@94259cd8be02ad2903ba34a22d9c13de21a74461 # v2.0 diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 21ae7d9c2ce2..280e5c87933f 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -20,6 +20,6 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repository - uses: actions/checkout@v4 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: Perform Dependency Review - uses: actions/dependency-review-action@v4 + uses: actions/dependency-review-action@0c155c5e8556a497adf53f2c18edabf945ed8e70 # v4.3.2 diff --git a/.github/workflows/gems-bump-version.yml b/.github/workflows/gems-bump-version.yml index 1a0203ebc0ca..2cfa139e78c2 100644 --- a/.github/workflows/gems-bump-version.yml +++ b/.github/workflows/gems-bump-version.yml @@ -1,5 +1,5 @@ name: Gems - Bump Version -on: # yamllint disable-line rule:truthy +on: # yamllint disable-line rule:truthy schedule: - cron: '25 1 * * THU' workflow_dispatch: @@ -24,13 +24,14 @@ jobs: app-id: ${{ secrets.DEPENDABOT_CORE_ACTION_AUTOMATION_APP_ID }} private-key: ${{ secrets.DEPENDABOT_CORE_ACTION_AUTOMATION_PRIVATE_KEY }} - - uses: actions/checkout@v4 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: token: ${{ steps.generate_token.outputs.token }} # Ensure we start from main in case the workflow is run from a branch ref: "main" - - uses: ruby/setup-ruby@v1 # bump-version.rb needs bundler + # bump-version.rb needs bundler + - uses: ruby/setup-ruby@cacc9f1c0b3f4eb8a16a6bb0ed10897b43b9de49 # v1.176.0 with: # Use the version of bundler specified in `updater/Gemfile.lock`. # Otherwise the generated PR will change `BUNDLED WITH` in diff --git a/.github/workflows/gems-release-to-rubygems.yml b/.github/workflows/gems-release-to-rubygems.yml index 3485cbf1ae11..19899acdc100 100644 --- a/.github/workflows/gems-release-to-rubygems.yml +++ b/.github/workflows/gems-release-to-rubygems.yml @@ -1,5 +1,5 @@ name: Gems - Release to RubyGems -on: # yamllint disable-line rule:truthy +on: # yamllint disable-line rule:truthy release: # It's fine to trigger on every release because if we tag a release w/o # bumping the Gem version, RubyGems will reject it with an error that the @@ -15,8 +15,8 @@ jobs: contents: read steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@v1 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: ruby/setup-ruby@cacc9f1c0b3f4eb8a16a6bb0ed10897b43b9de49 # v1.176.0 - run: | [ -d ~/.gem ] || mkdir ~/.gem echo "---" > ~/.gem/credentials diff --git a/.github/workflows/images-branch.yml b/.github/workflows/images-branch.yml index afd054b129d4..cd0efd62ff1c 100644 --- a/.github/workflows/images-branch.yml +++ b/.github/workflows/images-branch.yml @@ -24,7 +24,7 @@ jobs: decision: ${{ steps.decision.outputs.decision }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: submodules: recursive @@ -77,7 +77,7 @@ jobs: DEPENDABOT_UPDATER_VERSION: ${{ github.sha }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: submodules: recursive diff --git a/.github/workflows/images-latest.yml b/.github/workflows/images-latest.yml index 3f170068ed96..a072ec2543af 100644 --- a/.github/workflows/images-latest.yml +++ b/.github/workflows/images-latest.yml @@ -57,7 +57,7 @@ jobs: ECOSYSTEM: ${{ matrix.suite.ecosystem }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: submodules: recursive diff --git a/.github/workflows/images-updater-core.yml b/.github/workflows/images-updater-core.yml index 02a954f97ff9..b84be6e7d09f 100644 --- a/.github/workflows/images-updater-core.yml +++ b/.github/workflows/images-updater-core.yml @@ -18,7 +18,7 @@ jobs: packages: write steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: submodules: recursive diff --git a/.github/workflows/issue-labeler.yml b/.github/workflows/issue-labeler.yml index 9d5b7ef3410e..5ca39df31159 100644 --- a/.github/workflows/issue-labeler.yml +++ b/.github/workflows/issue-labeler.yml @@ -11,7 +11,7 @@ jobs: triage: runs-on: ubuntu-latest steps: - - uses: github/issue-labeler@v3.4 + - uses: github/issue-labeler@c1b0f9f52a63158c4adc09425e858e87b32e9685 # v3.4 with: configuration-path: .github/issue-labeler.yml enable-versioned-regex: 0 diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 72102933ea82..c4541f30a434 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -12,4 +12,4 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/labeler@v5 + - uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5.0.0 diff --git a/.github/workflows/smoke.yml b/.github/workflows/smoke.yml index cddf89fc2b75..40c652970d53 100644 --- a/.github/workflows/smoke.yml +++ b/.github/workflows/smoke.yml @@ -22,11 +22,11 @@ jobs: outputs: suites: ${{ steps.suites.outputs.suites }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: submodules: recursive - - uses: dorny/paths-filter@v3 + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 if: github.event_name != 'workflow_dispatch' id: changes with: @@ -64,7 +64,7 @@ jobs: matrix: suite: ${{ fromJSON(needs.discover.outputs.suites) }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: submodules: recursive @@ -76,7 +76,7 @@ jobs: - name: Restore Smoke Test id: cache-smoke-test - uses: actions/cache/restore@v4 + uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: smoke.yaml key: ${{ matrix.suite.sha }}-${{ matrix.suite.name }} @@ -89,7 +89,7 @@ jobs: - name: Cache Smoke Test if: steps.cache-smoke-test.outputs.cache-hit != 'true' - uses: actions/cache/save@v4 + uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: smoke.yaml key: ${{ steps.cache-smoke-test.outputs.cache-primary-key }} diff --git a/.github/workflows/sorbet.yml b/.github/workflows/sorbet.yml index ab1e70aa405b..756c445f9a72 100644 --- a/.github/workflows/sorbet.yml +++ b/.github/workflows/sorbet.yml @@ -14,9 +14,9 @@ jobs: name: Sorbet runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - - uses: ruby/setup-ruby@v1 + - uses: ruby/setup-ruby@cacc9f1c0b3f4eb8a16a6bb0ed10897b43b9de49 # v1.176.0 with: bundler-cache: true @@ -34,7 +34,7 @@ jobs: - run: bundle exec spoom coverage timeline --save - if: github.ref == 'refs/heads/main' && github.event_name == 'push' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 with: name: spoom_data path: ./spoom_data/ @@ -45,7 +45,7 @@ jobs: GH_TOKEN: ${{ github.token }} - if: github.ref == 'refs/heads/main' && github.event_name == 'push' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 with: name: spoom_report path: ./spoom_report.html diff --git a/.github/workflows/stalebot.yml b/.github/workflows/stalebot.yml index d621e3a59eff..20a4496adb1a 100644 --- a/.github/workflows/stalebot.yml +++ b/.github/workflows/stalebot.yml @@ -12,7 +12,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v9.0.0 + - uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9.0.0 name: Clean up stale PRs and Issues with: stale-pr-message: "👋 This pull request has been marked as stale because it has been open for 2 years with no activity. You can comment on the PR to hold stalebot off for a while, or do nothing. If you do nothing, this pull request will be closed eventually by the stalebot. Please see CONTRIBUTING.md for more policy details." diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 3b4f024b9604..3c06a16e31ff 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -51,7 +51,6 @@ RSpec/BeforeAfterAll: # Prefixes: when, with, without RSpec/ContextWording: Exclude: - - 'cargo/**/*' - 'common/**/*' - 'composer/**/*' - 'devcontainers/**/*' diff --git a/cargo/lib/dependabot/cargo/metadata_finder.rb b/cargo/lib/dependabot/cargo/metadata_finder.rb index caefd394a2a8..efce8f64ff2d 100644 --- a/cargo/lib/dependabot/cargo/metadata_finder.rb +++ b/cargo/lib/dependabot/cargo/metadata_finder.rb @@ -48,26 +48,40 @@ def crates_listing info = dependency.requirements.filter_map { |r| r[:source] }.first index = (info && info[:index]) || CRATES_IO_API + hdrs = build_headers(index, info) - # Default request headers + url = metadata_fetch_url(dependency, index) + response = fetch_metadata(url, hdrs) + + @crates_listing = parse_response(response, index) + end + + def build_headers(index, info) hdrs = { "User-Agent" => "Dependabot (dependabot.com)" } + return hdrs if index == CRATES_IO_API - if index != CRATES_IO_API - # Add authentication headers if credentials are present for this registry - credentials.find { |cred| cred["type"] == "cargo_registry" && cred["registry"] == info[:name] }&.tap do |cred| - hdrs["Authorization"] = "Token #{cred['token']}" - end + credentials.find { |cred| cred["type"] == "cargo_registry" && cred["registry"] == info[:name] }&.tap do |cred| + hdrs["Authorization"] = "Token #{cred['token']}" end - url = metadata_fetch_url(dependency, index) + hdrs + end - response = Excon.get( + def fetch_metadata(url, headers) + Excon.get( url, idempotent: true, - **SharedHelpers.excon_defaults(headers: hdrs) + **SharedHelpers.excon_defaults(headers: headers) ) + end - @crates_listing = JSON.parse(response.body) + def parse_response(response, index) + if index.start_with?("sparse+") + parsed_response = response.body.lines.map { |line| JSON.parse(line) } + { "versions" => parsed_response } + else + JSON.parse(response.body) + end end def metadata_fetch_url(dependency, index) diff --git a/cargo/lib/dependabot/cargo/update_checker/latest_version_finder.rb b/cargo/lib/dependabot/cargo/update_checker/latest_version_finder.rb index 48c7fc28f867..4df34707fc6a 100644 --- a/cargo/lib/dependabot/cargo/update_checker/latest_version_finder.rb +++ b/cargo/lib/dependabot/cargo/update_checker/latest_version_finder.rb @@ -97,46 +97,33 @@ def available_versions crates_listing .fetch("versions", []) .reject { |v| v["yanked"] } - .map { |v| version_class.new(v.fetch("num")) } + # Handle both default and sparse registry responses. + # Default registry uses "num" for version number. + # Sparse registry uses "vers" for version number. + .map do |v| + version_number = v["num"] || v["vers"] + version_class.new(version_number) + end end def crates_listing return @crates_listing unless @crates_listing.nil? - info = dependency.requirements.filter_map { |r| r[:source] }.first - index = (info && info[:index]) || CRATES_IO_API - - # Default request headers - hdrs = { "User-Agent" => "Dependabot (dependabot.com)" } - - if index != CRATES_IO_API - # Add authentication headers if credentials are present for this registry - registry_creds = credentials.find do |cred| - cred["type"] == "cargo_registry" && cred["registry"] == info[:name] - end - - unless registry_creds.nil? - # If there is a credential, but no actual token at this point, it means that dependabot-cli - # stripped the token from our credentials. In this case, the dependabot proxy will reintroduce - # the correct token, so we just use 'placeholder_token' as the token value. - token = registry_creds["token"] || "placeholder_token" + info = fetch_dependency_info + index = fetch_index(info) - hdrs["Authorization"] = token - end - end + hdrs = default_headers + hdrs.merge!(auth_headers(info)) if index != CRATES_IO_API url = metadata_fetch_url(dependency, index) # B4PR puts "Calling #{url} to fetch metadata for #{dependency.name} from #{index}" - response = Excon.get( - url, - idempotent: true, - **SharedHelpers.excon_defaults(headers: hdrs) - ) + response = fetch_response(url, hdrs) + return {} if response.status == 404 - @crates_listing = JSON.parse(response.body) + @crates_listing = parse_response(response, index) # B4PR puts "Fetched metadata for #{dependency.name} from #{index} successfully" @@ -145,6 +132,46 @@ def crates_listing @crates_listing end + def fetch_dependency_info + dependency.requirements.filter_map { |r| r[:source] }.first + end + + def fetch_index(info) + (info && info[:index]) || CRATES_IO_API + end + + def default_headers + { "User-Agent" => "Dependabot (dependabot.com)" } + end + + def auth_headers(info) + registry_creds = credentials.find do |cred| + cred["type"] == "cargo_registry" && cred["registry"] == info[:name] + end + + return {} if registry_creds.nil? + + token = registry_creds["token"] || "placeholder_token" + { "Authorization" => token } + end + + def fetch_response(url, headers) + Excon.get( + url, + idempotent: true, + **SharedHelpers.excon_defaults(headers: headers) + ) + end + + def parse_response(response, index) + if index.start_with?("sparse+") + parsed_response = response.body.lines.map { |line| JSON.parse(line) } + { "versions" => parsed_response } + else + JSON.parse(response.body) + end + end + def metadata_fetch_url(dependency, index) return "#{index}/#{dependency.name}" if index == CRATES_IO_API diff --git a/cargo/spec/dependabot/cargo/file_fetcher_spec.rb b/cargo/spec/dependabot/cargo/file_fetcher_spec.rb index 4e00ceac13a3..0cfd307a52cb 100644 --- a/cargo/spec/dependabot/cargo/file_fetcher_spec.rb +++ b/cargo/spec/dependabot/cargo/file_fetcher_spec.rb @@ -250,7 +250,7 @@ fixture("github", "contents_cargo_manifest_path_deps.json") end - context "that is fetchable" do + context "when the workspace is fetchable" do before do stub_request(:get, url + "src/s3/Cargo.toml?ref=sha") .with(headers: { "Authorization" => "token token" }) @@ -295,7 +295,7 @@ end end - context "for a target dependency" do + context "when dealing with a target dependency" do let(:parent_fixture) do fixture( "github", @@ -309,7 +309,7 @@ end end - context "for a replacement source" do + context "when dealing with a replacement source" do let(:parent_fixture) do fixture("github", "contents_cargo_manifest_replacement_path.json") end @@ -320,7 +320,7 @@ end end - context "for a patched source" do + context "when dealing with a patched source" do let(:parent_fixture) do fixture("github", "contents_cargo_manifest_patched_path.json") end @@ -379,7 +379,7 @@ end end - context "and includes another path dependency" do + context "when including another path dependency" do let(:path_dep_fixture) do fixture("github", "contents_cargo_manifest_path_deps.json") end @@ -403,7 +403,7 @@ end end - context "that is not fetchable" do + context "when the workspace is not fetchable" do before do stub_request(:get, url + "src/s3/Cargo.toml?ref=sha") .with(headers: { "Authorization" => "token token" }) @@ -423,7 +423,7 @@ end end - context "for a replacement source" do + context "when dealing with a replacement source" do let(:parent_fixture) do fixture("github", "contents_cargo_manifest_replacement_path.json") end @@ -478,7 +478,7 @@ fixture("github", "contents_cargo_manifest_workspace_root.json") end - context "that is fetchable" do + context "when the workspace is fetchable" do before do stub_request(:get, url + "lib/sub_crate/Cargo.toml?ref=sha") .with(headers: { "Authorization" => "token token" }) @@ -493,7 +493,7 @@ .to match_array(%w(Cargo.toml .cargo/config.toml lib/sub_crate/Cargo.toml)) end - context "and specifies the dependency implicitly" do + context "when specifying the dependency implicitly" do let(:parent_fixture) do fixture("github", "contents_cargo_manifest_workspace_implicit.json") end @@ -511,7 +511,7 @@ end end - context "and specifies the dependency as a path dependency, too" do + context "when specifying the dependency as a path dependency as well" do let(:parent_fixture) do fixture( "github", @@ -528,7 +528,7 @@ end end - context "that is not fetchable" do + context "when the workspace is not fetchable" do before do stub_request(:get, url + "lib/sub_crate/Cargo.toml?ref=sha") .with(headers: { "Authorization" => "token token" }) @@ -548,7 +548,7 @@ end end - context "that is in a submodule" do + context "when the project is in a submodule" do before do # This file doesn't exist because sub_crate is a submodule, so returns a 404 stub_request(:get, url + "lib/sub_crate/Cargo.toml?ref=sha") @@ -577,7 +577,7 @@ end end - context "that specifies a directory of packages" do + context "when specifying a directory of packages" do let(:parent_fixture) do fixture("github", "contents_cargo_manifest_workspace_root_glob.json") end diff --git a/cargo/spec/dependabot/cargo/file_parser_spec.rb b/cargo/spec/dependabot/cargo/file_parser_spec.rb index 31a1010c2866..619f71763e92 100644 --- a/cargo/spec/dependabot/cargo/file_parser_spec.rb +++ b/cargo/spec/dependabot/cargo/file_parser_spec.rb @@ -109,7 +109,7 @@ end end - context "which is part of a workspace but not the root" do + context "when the project is part of a workspace but not the root" do let(:manifest_fixture_name) { "workspace_child" } it "raises a helpful error" do @@ -521,7 +521,7 @@ end end - context "that is unparseable" do + context "when the input is unparseable" do let(:manifest_fixture_name) { "unparseable" } it "raises a DependencyFileNotParseable error" do @@ -532,7 +532,7 @@ end end - context "that have value overwrite issues" do + context "when there are value overwrite issues" do let(:manifest_fixture_name) { "unparseable_value_overwrite" } it "raises a DependencyFileNotParseable error" do @@ -838,7 +838,7 @@ it { is_expected.to eq([]) } end - context "that is unparseable" do + context "when the input is unparseable" do let(:lockfile_fixture_name) { "unparseable" } it "raises a DependencyFileNotParseable error" do diff --git a/cargo/spec/dependabot/cargo/file_updater/lockfile_updater_spec.rb b/cargo/spec/dependabot/cargo/file_updater/lockfile_updater_spec.rb index 2987b70e6d39..920f68a31bfc 100644 --- a/cargo/spec/dependabot/cargo/file_updater/lockfile_updater_spec.rb +++ b/cargo/spec/dependabot/cargo/file_updater/lockfile_updater_spec.rb @@ -91,7 +91,7 @@ end end - context "because an existing requirement is no good" do + context "when an existing requirement is not sufficient" do let(:dependency_version) { "0.1.38" } let(:requirements) do [{ file: "Cargo.toml", requirement: "0.3.20", groups: [], source: nil }] diff --git a/cargo/spec/dependabot/cargo/file_updater/manifest_updater_spec.rb b/cargo/spec/dependabot/cargo/file_updater/manifest_updater_spec.rb index b142aea2f7d8..b82d27b32d09 100644 --- a/cargo/spec/dependabot/cargo/file_updater/manifest_updater_spec.rb +++ b/cargo/spec/dependabot/cargo/file_updater/manifest_updater_spec.rb @@ -41,7 +41,7 @@ describe "#updated_manifest_content" do subject(:updated_manifest_content) { updater.updated_manifest_content } - context "if no files have changed" do + context "when no files have changed" do it { is_expected.to eq(manifest.content) } end @@ -245,7 +245,7 @@ }] end - context "that is a build dependency" do + context "when dealing with a build dependency" do let(:manifest_fixture_name) { "feature_build_dependency" } let(:requirements) do [{ diff --git a/cargo/spec/dependabot/cargo/file_updater_spec.rb b/cargo/spec/dependabot/cargo/file_updater_spec.rb index 0c945cd98856..3aef52b74aa7 100644 --- a/cargo/spec/dependabot/cargo/file_updater_spec.rb +++ b/cargo/spec/dependabot/cargo/file_updater_spec.rb @@ -74,7 +74,7 @@ context "without a lockfile" do let(:files) { [manifest] } - context "if no files have changed" do + context "when no files have changed" do it "raises a helpful error" do expect { updater.updated_dependency_files } .to raise_error("No files changed!") diff --git a/cargo/spec/dependabot/cargo/metadata_finder_spec.rb b/cargo/spec/dependabot/cargo/metadata_finder_spec.rb index 5bde4d3474dc..2c566b666218 100644 --- a/cargo/spec/dependabot/cargo/metadata_finder_spec.rb +++ b/cargo/spec/dependabot/cargo/metadata_finder_spec.rb @@ -98,7 +98,7 @@ it { is_expected.to eq("https://github.com/rust-lang-nursery/bitflags") } end - context "for a git source" do + context "when dealing with a git source" do let(:crates_response) { nil } let(:dependency_source) do { type: "git", url: "https://github.com/my_fork/bitflags" } @@ -106,7 +106,7 @@ it { is_expected.to eq("https://github.com/my_fork/bitflags") } - context "that doesn't match a supported source" do + context "when it doesn't match a supported source" do let(:dependency_source) do { type: "git", url: "https://example.com/my_fork/bitflags" } end diff --git a/cargo/spec/dependabot/cargo/requirement_spec.rb b/cargo/spec/dependabot/cargo/requirement_spec.rb index 2db691959a82..d57c091cfa68 100644 --- a/cargo/spec/dependabot/cargo/requirement_spec.rb +++ b/cargo/spec/dependabot/cargo/requirement_spec.rb @@ -46,7 +46,7 @@ let(:requirement_string) { "1.1.*" } it { is_expected.to eq(described_class.new("~> 1.1.0")) } - context "prefixed with a caret" do + context "when prefixed with a caret" do let(:requirement_string) { "^1.1.*" } it { is_expected.to eq(described_class.new("~> 1.1.0")) } end @@ -59,7 +59,7 @@ end context "with a caret version" do - context "specified to 3 dp" do + context "when specified to 3 dp" do let(:requirement_string) { "^1.2.3" } it { is_expected.to eq(described_class.new(">= 1.2.3", "< 2.0.0")) } @@ -67,14 +67,14 @@ let(:requirement_string) { "^0.2.3" } it { is_expected.to eq(described_class.new(">= 0.2.3", "< 0.3.0")) } - context "and a zero minor" do + context "when a zero minor is present" do let(:requirement_string) { "^0.0.3" } it { is_expected.to eq(described_class.new(">= 0.0.3", "< 0.0.4")) } end end end - context "specified to 2 dp" do + context "when specified to 2 dp" do let(:requirement_string) { "^1.2" } it { is_expected.to eq(described_class.new(">= 1.2", "< 2.0")) } @@ -82,14 +82,14 @@ let(:requirement_string) { "^0.2" } it { is_expected.to eq(described_class.new(">= 0.2", "< 0.3")) } - context "and a zero minor" do + context "when a zero minor is present" do let(:requirement_string) { "^0.0" } it { is_expected.to eq(described_class.new(">= 0.0", "< 0.1")) } end end end - context "specified to 1 dp" do + context "when specified to 1 dp" do let(:requirement_string) { "^1" } it { is_expected.to eq(described_class.new(">= 1", "< 2")) } @@ -101,17 +101,17 @@ end context "with a ~ version" do - context "specified to 3 dp" do + context "when specified to 3 dp" do let(:requirement_string) { "~1.5.1" } it { is_expected.to eq(described_class.new("~> 1.5.1")) } end - context "specified to 2 dp" do + context "when specified to 2 dp" do let(:requirement_string) { "~1.5" } it { is_expected.to eq(described_class.new("~> 1.5.0")) } end - context "specified to 1 dp" do + context "when specified to 1 dp" do let(:requirement_string) { "~1" } it { is_expected.to eq(described_class.new("~> 1.0")) } end diff --git a/cargo/spec/dependabot/cargo/update_checker/file_preparer_spec.rb b/cargo/spec/dependabot/cargo/update_checker/file_preparer_spec.rb index fca2047b90b1..bfab5bcbf5ad 100644 --- a/cargo/spec/dependabot/cargo/update_checker/file_preparer_spec.rb +++ b/cargo/spec/dependabot/cargo/update_checker/file_preparer_spec.rb @@ -82,7 +82,7 @@ .to include('regex = ">= 0.1.41"') end - context "the a target-specific dependency" do + context "when dealing with a target-specific dependency" do let(:manifest_fixture_name) { "target_dependency" } let(:lockfile_fixture_name) { "target_dependency" } let(:dependency_name) { "time" } @@ -158,7 +158,7 @@ .to include('regex = ">= 0.1.41"') end - context "and a latest_allowable_version" do + context "when a latest_allowable_version is present" do let(:latest_allowable_version) { Gem::Version.new("1.6.0") } it "updates the requirement" do @@ -166,7 +166,7 @@ .to include('regex = ">= 0.1.41, <= 1.6.0"') end - context "that is lower than the current lower bound" do + context "when the value is lower than the current lower bound" do let(:latest_allowable_version) { Gem::Version.new("0.1.0") } it "updates the requirement" do @@ -224,7 +224,7 @@ .to include('version = ">= 1.0.0"') end - context "using ssh" do + context "when using ssh" do let(:manifest_fixture_name) { "git_dependency_ssh" } let(:lockfile_fixture_name) { "git_dependency_ssh" } diff --git a/cargo/spec/dependabot/cargo/update_checker/latest_version_finder_spec.rb b/cargo/spec/dependabot/cargo/update_checker/latest_version_finder_spec.rb index 2b4e477ccefa..6d85f2cbd037 100644 --- a/cargo/spec/dependabot/cargo/update_checker/latest_version_finder_spec.rb +++ b/cargo/spec/dependabot/cargo/update_checker/latest_version_finder_spec.rb @@ -7,13 +7,12 @@ require "dependabot/cargo/update_checker/latest_version_finder" RSpec.describe Dependabot::Cargo::UpdateChecker::LatestVersionFinder do - before do - stub_request(:get, crates_url).to_return(status: 200, body: crates_response) - end let(:crates_url) { "https://crates.io/api/v1/crates/#{dependency_name}" } let(:crates_response) { fixture("crates_io_responses", crates_fixture_name) } let(:crates_fixture_name) { "#{dependency_name}.json" } - + let(:ignored_versions) { [] } + let(:raise_on_ignored) { false } + let(:security_advisories) { [] } let(:finder) do described_class.new( dependency: dependency, @@ -24,10 +23,6 @@ security_advisories: security_advisories ) end - - let(:ignored_versions) { [] } - let(:raise_on_ignored) { false } - let(:security_advisories) { [] } let(:credentials) do [{ "type" => "git_source", @@ -66,6 +61,10 @@ describe "#latest_version" do subject { finder.latest_version } + before do + stub_request(:get, crates_url).to_return(status: 200, body: crates_response) + end + it { is_expected.to eq(Gem::Version.new("0.1.40")) } context "when the latest version is being ignored" do @@ -111,13 +110,13 @@ let(:dependency_version) { "2.0.0" } it { is_expected.to eq(Gem::Version.new("2.1.0")) } - context "and the user wants a pre-release" do - context "because their current version is a pre-release" do + context "when the user wants a pre-release" do + context "when their current version is a pre-release" do let(:dependency_version) { "2.0.0-pre4" } it { is_expected.to eq(Gem::Version.new("3.0.0-pre1")) } end - context "because their requirements say they want pre-releases" do + context "when their requirements indicate a preference for pre-releases" do let(:requirements) do [{ file: "Cargo.toml", @@ -131,7 +130,7 @@ end end - context "raise_on_ignored when later versions are allowed" do + context "when raise_on_ignored is set and later versions are allowed" do let(:raise_on_ignored) { true } it "doesn't raise an error" do expect { subject }.to_not raise_error @@ -142,7 +141,7 @@ let(:dependency_version) { "0.1.40" } it { is_expected.to eq(Gem::Version.new("0.1.40")) } - context "raise_on_ignored" do + context "when raise_on_ignored is enabled" do let(:raise_on_ignored) { true } it "doesn't raise an error" do expect { subject }.to_not raise_error @@ -154,7 +153,7 @@ let(:ignored_versions) { ["> 0.1.38"] } it { is_expected.to eq(Gem::Version.new("0.1.38")) } - context "raise_on_ignored" do + context "when raise_on_ignored is enabled" do let(:raise_on_ignored) { true } it "raises an error" do expect { subject }.to raise_error(Dependabot::AllVersionsIgnored) @@ -165,7 +164,7 @@ context "when the dependency version isn't known" do let(:dependency_version) { nil } - context "raise_on_ignored" do + context "when raise_on_ignored is enabled" do let(:raise_on_ignored) { true } it "doesn't raise an error" do expect { subject }.to_not raise_error @@ -177,6 +176,10 @@ describe "#lowest_security_fix_version" do subject { finder.lowest_security_fix_version } + before do + stub_request(:get, crates_url).to_return(status: 200, body: crates_response) + end + let(:dependency_name) { "time" } let(:dependency_version) { "0.1.12" } let(:security_advisories) do @@ -201,7 +204,7 @@ expect(subject).to be_nil end - context "raise_on_ignored" do + context "when raise_on_ignored is enabled" do let(:raise_on_ignored) { true } it "raises an error" do expect { subject }.to raise_error(Dependabot::AllVersionsIgnored) @@ -223,13 +226,13 @@ end it { is_expected.to eq(Gem::Version.new("2.0.0")) } - context "and the user wants a pre-release" do - context "because their current version is a pre-release" do + context "when the user wants a pre-release" do + context "when their current version is a pre-release" do let(:dependency_version) { "2.0.0-pre1" } it { is_expected.to eq(Gem::Version.new("2.0.0-pre3")) } end - context "because their requirements say they want pre-releases" do + context "when their requirements indicate a preference for pre-releases" do let(:requirements) do [{ file: "Cargo.toml", @@ -243,4 +246,192 @@ end end end + + # Tests for sparse registry responses + describe "Sparse registry response handling" do + let(:sparse_registry_url) { "https://cargo.cloudsmith.io/honeyankit/test/he/ll/hello-world" } + let(:sparse_registry_response) { fixture("private_registry_responses", crates_fixture_name) } + let(:crates_fixture_name) { "#{dependency_name}.json" } + + let(:credentials) do + [{ + "type" => "cargo_registry", + "cargo_registry" => "honeyankit-test", + "url" => "https://cargo.cloudsmith.io/honeyankit/test/", + "token" => "token" + }] + end + let(:dependency_name) { "hello-world" } + let(:dependency_version) { "1.0.0" } + let(:requirements) do + [{ + file: "Cargo.toml", + requirement: "1.0.0", + groups: ["dependencies"], + source: { + type: "registry", + name: "honeyankit-test", + index: "sparse+https://cargo.cloudsmith.io/honeyankit/test/", + dl: "https://dl.cloudsmith.io/basic/honeyankit/test/cargo/{crate}-{version}.crate", + api: "https://cargo.cloudsmith.io/honeyankit/test" + } + }] + end + + describe "#latest_version" do + subject { finder.latest_version } + before do + stub_request(:get, sparse_registry_url).to_return(status: 200, body: sparse_registry_response) + end + + it { is_expected.to eq(Gem::Version.new("1.0.1")) } + + context "when the latest version is being ignored" do + let(:ignored_versions) { [">= 1.0.1, < 2.0"] } + it { is_expected.to eq(Gem::Version.new("1.0.0")) } + end + + context "when the sparse registry link resolves to a 'Not Found' page" do + before do + stub_request(:get, sparse_registry_url) + .to_return(status: 404, body: sparse_registry_response) + end + let(:crates_fixture_name) { "not_found.json" } + + it { is_expected.to be_nil } + end + + context "when the latest version is a pre-release" do + let(:sparse_registry_response) do + <<~BODY + {"name": "hello-world", "vers": "1.0.0", "deps": [], "cksum": "b2c263921f1114820f4acc6b542d72bbc859ce7023c5b235346b157074dcccc7", "features": {}, "yanked": false, "links": null} + {"name": "hello-world", "vers": "2.0.0-pre1", "deps": [], "cksum": "8a55b58def1ecc7aa8590c7078f379ec9a85328363ffb81d4354314b132b95c4", "features": {}, "yanked": false, "links": null} + BODY + end + it { is_expected.to eq(Gem::Version.new("1.0.0")) } + + context "with the user wants a pre-release" do + let(:requirements) do + [{ + file: "Cargo.toml", + requirement: "~2.0.0-pre1", + groups: ["dependencies"], + source: { + type: "registry", + name: "honeyankit-test", + index: "sparse+https://cargo.cloudsmith.io/honeyankit/test/", + dl: "https://dl.cloudsmith.io/basic/honeyankit/test/cargo/{crate}-{version}.crate", + api: "https://cargo.cloudsmith.io/honeyankit/test" + } + }] + end + it { is_expected.to eq(Gem::Version.new("2.0.0-pre1")) } + end + end + + context "when already on the latest version" do + let(:dependency_version) { "1.0.1" } + it { is_expected.to eq(Gem::Version.new("1.0.1")) } + end + + context "when all later versions are being ignored" do + let(:ignored_versions) { ["> 1.0.0"] } + it { is_expected.to eq(Gem::Version.new("1.0.0")) } + + context "with raise_on_ignored" do + let(:raise_on_ignored) { true } + it "raises an error" do + expect { subject }.to raise_error(Dependabot::AllVersionsIgnored) + end + end + end + end + + describe "#lowest_security_fix_version" do + subject { finder.lowest_security_fix_version } + + before do + stub_request(:get, sparse_registry_url).to_return(status: 200, body: sparse_registry_response) + end + + let(:dependency_name) { "hello-world" } + let(:dependency_version) { "1.0.0" } + let(:security_advisories) do + [ + Dependabot::SecurityAdvisory.new( + dependency_name: dependency_name, + package_manager: "cargo", + vulnerable_versions: ["<= 1.0.0"] + ) + ] + end + it { is_expected.to eq(Gem::Version.new("1.0.1")) } + + context "when the lowest version is being ignored" do + let(:ignored_versions) { [">= 1.0.0, < 1.0.1"] } + it { is_expected.to eq(Gem::Version.new("1.0.1")) } + end + + context "when all versions are being ignored" do + let(:ignored_versions) { [">= 0"] } + it "returns nil" do + expect(subject).to be_nil + end + + context "with raise_on_ignored" do + let(:raise_on_ignored) { true } + it "raises an error" do + expect { subject }.to raise_error(Dependabot::AllVersionsIgnored) + end + end + end + + context "when the lowest fixed version is a pre-release" do + let(:sparse_registry_response) do + <<~BODY + {"name": "hello-world", "vers": "1.0.0", "deps": [], "cksum": "b2c263921f1114820f4acc6b542d72bbc859ce7023c5b235346b157074dcccc7", "features": {}, "yanked": false, "links": null} + {"name": "hello-world", "vers": "2.0.0", "deps": [], "cksum": "b2c263921f1114820f4acc6b542d72bbc859ce7023c5b235346b157074dcccc8", "features": {}, "yanked": false, "links": null} + {"name": "hello-world", "vers": "2.0.0-pre1", "deps": [], "cksum": "8a55b58def1ecc7aa8590c7078f379ec9a85328363ffb81d4354314b132b95c4", "features": {}, "yanked": false, "links": null} + {"name": "hello-world", "vers": "2.0.0-pre2", "deps": [], "cksum": "8a55b58def1ecc7aa8590c7078f379ec9a85328363ffb81d4354314b132b95f6", "features": {}, "yanked": false, "links": null} + {"name": "hello-world", "vers": "2.0.0-pre3", "deps": [], "cksum": "8a55b58def1ecc7aa8590c7078f379ec9a85328363ffb81d4354314b132b95d6", "features": {}, "yanked": false, "links": null} + BODY + end + let(:security_advisories) do + [ + Dependabot::SecurityAdvisory.new( + dependency_name: dependency_name, + package_manager: "cargo", + vulnerable_versions: ["<= 2.0.0-pre2"] + ) + ] + end + it { is_expected.to eq(Gem::Version.new("2.0.0")) } + + context "with the user wants a pre-release" do + context "when their current version is a pre-release" do + let(:dependency_version) { "2.0.0-pre1" } + it { is_expected.to eq(Gem::Version.new("2.0.0-pre3")) } + end + + context "when their requirements say they want pre-releases" do + let(:requirements) do + [{ + file: "Cargo.toml", + requirement: "~2.0.0-pre1", + groups: ["dependencies"], + source: { + type: "registry", + name: "honeyankit-test", + index: "sparse+https://cargo.cloudsmith.io/honeyankit/test/", + dl: "https://dl.cloudsmith.io/basic/honeyankit/test/cargo/{crate}-{version}.crate", + api: "https://cargo.cloudsmith.io/honeyankit/test" + } + }] + end + it { is_expected.to eq(Gem::Version.new("2.0.0-pre3")) } + end + end + end + end + end end diff --git a/cargo/spec/dependabot/cargo/update_checker/requirements_updater_spec.rb b/cargo/spec/dependabot/cargo/update_checker/requirements_updater_spec.rb index ff873620db94..6bb16264fdea 100644 --- a/cargo/spec/dependabot/cargo/update_checker/requirements_updater_spec.rb +++ b/cargo/spec/dependabot/cargo/update_checker/requirements_updater_spec.rb @@ -78,56 +78,56 @@ end end - context "for a bump_versions strategy" do + context "when using a bump_versions strategy" do let(:update_strategy) { Dependabot::RequirementsUpdateStrategy::BumpVersions } context "when there is a latest version" do - context "and a full version was previously specified" do + context "when a full version was previously specified" do let(:req_string) { "1.2.3" } its([:requirement]) { is_expected.to eq("1.5.0") } end - context "and an equality requirement was previously specified" do + context "when an equality requirement was previously specified" do let(:req_string) { "=1.2.3" } its([:requirement]) { is_expected.to eq("=1.5.0") } end - context "and a partial version was previously specified" do + context "when a partial version was previously specified" do let(:req_string) { "0.1" } its([:requirement]) { is_expected.to eq("1.5") } end - context "and only the major part was previously specified" do + context "when only the major part was previously specified" do let(:req_string) { "1" } let(:target_version) { "4.5.0" } its([:requirement]) { is_expected.to eq("4") } end - context "and the new version has fewer digits than the old one" do + context "when the new version has fewer digits than the old one" do let(:req_string) { "1.1.0.1" } its([:requirement]) { is_expected.to eq("1.5.0") } end - context "and the new version has much fewer digits than the old one" do + context "when the new version has significantly fewer digits than the old one" do let(:req_string) { "1.1.0.1" } let(:target_version) { "4" } its([:requirement]) { is_expected.to eq("4") } end - context "and a caret was previously specified" do + context "when a caret was previously specified" do let(:req_string) { "^1.2.3" } its([:requirement]) { is_expected.to eq("^1.5.0") } end - context "and a pre-release was previously specified" do + context "when a pre-release was previously specified" do let(:req_string) { "^1.2.3-rc1" } its([:requirement]) { is_expected.to eq("^1.5.0") } - context "that needs updating" do + context "when needing an update" do let(:req_string) { "1.2.3-rc1" } its([:requirement]) { is_expected.to eq("1.5.0") } - context "to a new pre-release version" do + context "when transitioning to a new pre-release version" do let(:req_string) { "1.2.3-beta" } let(:target_version) { "1.2.3-beta.2" } its([:requirement]) { is_expected.to eq("1.2.3-beta.2") } @@ -150,32 +150,32 @@ its([:requirement]) { is_expected.to eq(:unfixable) } end - context "and there were multiple range specifications" do + context "when there were multiple range specifications" do let(:req_string) { "> 1.0.0, < 1.2.0" } its([:requirement]) { is_expected.to eq("> 1.0.0, < 1.6.0") } - context "already valid" do + context "when already valid" do let(:req_string) { "> 1.0.0, < 1.7.0" } its([:requirement]) { is_expected.to eq(req_string) } end - context "that include a pre-release" do + context "when including a pre-release" do let(:req_string) { ">=1.2.0, <1.4.0-dev" } its([:requirement]) { is_expected.to eq(">=1.2.0, <1.6.0") } end end - context "and an *.* was previously specified" do + context "when an *.* was previously specified" do let(:req_string) { "^0.*.*" } its([:requirement]) { is_expected.to eq("^1.*.*") } end - context "and an *.* was previously specified with four places" do + context "when an *.* was previously specified with four places" do let(:req_string) { "^0.*.*.rc1" } its([:requirement]) { is_expected.to eq("^1.*.*") } end - context "and there were multiple requirements" do + context "when there were multiple requirements" do let(:requirements) do [ { @@ -215,7 +215,7 @@ end end - context "and the target version has a build annotation" do + context "when the target version has a build annotation" do let(:req_string) { "1.2.3" } let(:target_version) { "1.5.0+build.1" } its([:requirement]) { is_expected.to eq("1.5.0") } @@ -223,7 +223,7 @@ end end - context "for a bump_versions_if_necessary strategy" do + context "when using a bump_versions_if_necessary strategy" do let(:update_strategy) { Dependabot::RequirementsUpdateStrategy::BumpVersionsIfNecessary } context "when there is no latest version" do @@ -232,52 +232,52 @@ end context "when there is a latest version" do - context "and a full version was previously specified" do + context "when a full version was previously specified" do let(:req_string) { "1.2.3" } its([:requirement]) { is_expected.to eq(req_string) } end - context "and an equality requirement was previously specified" do + context "when an equality requirement was previously specified" do let(:req_string) { "=1.2.3" } its([:requirement]) { is_expected.to eq("=1.5.0") } end - context "and a partial version was previously specified" do + context "when a partial version was previously specified" do let(:req_string) { "0.1" } its([:requirement]) { is_expected.to eq("1.5") } end - context "and only the major part was previously specified" do + context "when only the major part was previously specified" do let(:req_string) { "1" } let(:target_version) { "4.5.0" } its([:requirement]) { is_expected.to eq("4") } end - context "and the new version has fewer digits than the old one" do + context "when the new version has fewer digits than the old one" do let(:req_string) { "0.1.0.1" } its([:requirement]) { is_expected.to eq("1.5.0") } end - context "and the new version has much fewer digits than the old one" do + context "when the new version has significantly fewer digits than the old one" do let(:req_string) { "1.1.0.1" } let(:target_version) { "4" } its([:requirement]) { is_expected.to eq("4") } end - context "and a caret was previously specified" do + context "when a caret was previously specified" do let(:req_string) { "^1.2.3" } its([:requirement]) { is_expected.to eq(req_string) } end - context "and a pre-release was previously specified" do + context "when a pre-release was previously specified" do let(:req_string) { "^1.2.3-rc1" } its([:requirement]) { is_expected.to eq(req_string) } - context "that needs updating" do + context "when needing an update" do let(:req_string) { "0.2.3-rc1" } its([:requirement]) { is_expected.to eq("1.5.0") } - context "to a new pre-release version" do + context "when transitioning to a new pre-release version" do let(:req_string) { "0.2.3-beta" } let(:target_version) { "1.2.3-beta.2" } its([:requirement]) { is_expected.to eq("1.2.3-beta.2") } @@ -300,32 +300,32 @@ its([:requirement]) { is_expected.to eq(:unfixable) } end - context "and there were multiple range specifications" do + context "when there are multiple range specifications" do let(:req_string) { "> 1.0.0, < 1.2.0" } its([:requirement]) { is_expected.to eq("> 1.0.0, < 1.6.0") } - context "already valid" do + context "when already valid" do let(:req_string) { "> 1.0.0, < 1.7.0" } its([:requirement]) { is_expected.to eq(req_string) } end - context "that include a pre-release" do + context "when including a pre-release" do let(:req_string) { ">=1.2.0, <1.4.0-dev" } its([:requirement]) { is_expected.to eq(">=1.2.0, <1.6.0") } end end - context "and an *.* was previously specified" do + context "when an *.* was previously specified" do let(:req_string) { "^0.*.*" } its([:requirement]) { is_expected.to eq("^1.*.*") } end - context "and an *.* was previously specified with four places" do + context "when an *.* was previously specified with four places" do let(:req_string) { "^0.*.*.rc1" } its([:requirement]) { is_expected.to eq("^1.*.*") } end - context "and there were multiple requirements" do + context "when there are multiple requirements" do let(:requirements) do [ { @@ -367,7 +367,7 @@ end end - context "for a lockfile_only strategy" do + context "when using a lockfile_only strategy" do let(:update_strategy) { Dependabot::RequirementsUpdateStrategy::LockfileOnly } it "does not change any requirements" do diff --git a/cargo/spec/dependabot/cargo/update_checker/version_resolver_spec.rb b/cargo/spec/dependabot/cargo/update_checker/version_resolver_spec.rb index 005f3990434a..81ac1366f4c3 100644 --- a/cargo/spec/dependabot/cargo/update_checker/version_resolver_spec.rb +++ b/cargo/spec/dependabot/cargo/update_checker/version_resolver_spec.rb @@ -179,7 +179,7 @@ end end - context "using a feature that is not enabled" do + context "when using a feature that is not enabled" do let(:manifest_fixture_name) { "disabled_feature" } let(:lockfile_fixture_name) { "bare_version_specified" } @@ -212,7 +212,7 @@ end end - context "which isn't the package being updated" do + context "when it isn't the package being updated" do let(:dependency_name) { "regex" } let(:string_req) { "0.1.41" } @@ -298,7 +298,7 @@ it { is_expected.to eq(dependency_version) } end - context "that is unreachable" do + context "when it is unreachable" do let(:manifest_fixture_name) { "git_dependency_unreachable" } let(:lockfile_fixture_name) { "git_dependency_unreachable" } let(:git_url) do @@ -321,7 +321,7 @@ end end - context "but is skipped by the parser (because it has multiple URLs)" do + context "when skipped by the parser due to multiple URLs)" do let(:unprepared_dependency_files) do [manifest, workspace_child, workspace_child2] end @@ -482,7 +482,7 @@ it { is_expected.to be >= Gem::Version.new("0.4.4") } - context "but Dependabot has been asked to run on only a child" do + context "when Dependabot has been asked to run on only a child" do let(:unprepared_dependency_files) { [manifest, workspace_child] } let(:manifest) do Dependabot::DependencyFile.new( @@ -516,7 +516,7 @@ end end - context "but it is not correctly set up" do + context "when it is not correctly set up" do let(:unprepared_dependency_files) do [manifest, workspace_child] end diff --git a/cargo/spec/dependabot/cargo/update_checker_spec.rb b/cargo/spec/dependabot/cargo/update_checker_spec.rb index 4cbb5a20d9f2..93594723e0c3 100644 --- a/cargo/spec/dependabot/cargo/update_checker_spec.rb +++ b/cargo/spec/dependabot/cargo/update_checker_spec.rb @@ -74,11 +74,11 @@ describe "#can_update?" do subject { checker.can_update?(requirements_to_unlock: :own) } - context "given an outdated dependency" do + context "when given an outdated dependency" do it { is_expected.to be_truthy } end - context "given an up-to-date dependency" do + context "when given an up-to-date dependency" do let(:dependency_version) { "0.1.40" } it { is_expected.to be_falsey } end diff --git a/cargo/spec/fixtures/private_registry_responses/hello-world.json b/cargo/spec/fixtures/private_registry_responses/hello-world.json new file mode 100644 index 000000000000..4e5cc3e234bc --- /dev/null +++ b/cargo/spec/fixtures/private_registry_responses/hello-world.json @@ -0,0 +1,2 @@ +{"name": "hello-world", "vers": "1.0.0", "deps": [], "cksum": "b2c263921f1114820f4acc6b542d72bbc859ce7023c5b235346b157074dcccc7", "features": {}, "yanked": false, "links": null} +{"name": "hello-world", "vers": "1.0.1", "deps": [], "cksum": "8a55b58def1ecc7aa8590c7078f379ec9a85328363ffb81d4354314b132b95c4", "features": {}, "yanked": false, "links": null} \ No newline at end of file diff --git a/cargo/spec/fixtures/private_registry_responses/not_found.json b/cargo/spec/fixtures/private_registry_responses/not_found.json new file mode 100644 index 000000000000..4a1f2b997789 --- /dev/null +++ b/cargo/spec/fixtures/private_registry_responses/not_found.json @@ -0,0 +1 @@ +Invalid url. \ No newline at end of file diff --git a/npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/version_resolver.rb b/npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/version_resolver.rb index ff34ac03c911..3026b55d5b5b 100644 --- a/npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/version_resolver.rb +++ b/npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/version_resolver.rb @@ -1,6 +1,8 @@ -# typed: false +# typed: true # frozen_string_literal: true +require "sorbet-runtime" + require "dependabot/errors" require "dependabot/git_commit_checker" require "dependabot/logger" @@ -21,6 +23,8 @@ module Dependabot module NpmAndYarn class UpdateChecker class VersionResolver + extend T::Sig + require_relative "latest_version_finder" TIGHTLY_COUPLED_MONOREPOS = { @@ -162,6 +166,7 @@ def dependency_updates_from_full_unlock private + sig { returns(Dependabot::Dependency) } attr_reader :dependency attr_reader :credentials attr_reader :dependency_files @@ -356,32 +361,34 @@ def fetch_peer_dependency_errors(version:) [] end + # rubocop:disable Metrics/AbcSize + sig { params(message: String).returns(T::Array[T::Hash[String, T.nilable(String)]]) } def handle_peer_dependency_errors(message) errors = [] if message.match?(NPM6_PEER_DEP_ERROR_REGEX) message.scan(NPM6_PEER_DEP_ERROR_REGEX) do - errors << Regexp.last_match.named_captures + errors << Regexp.last_match&.named_captures end elsif message.match?(NPM8_PEER_DEP_ERROR_REGEX) message.scan(NPM8_PEER_DEP_ERROR_REGEX) do - errors << Regexp.last_match.named_captures + errors << T.must(Regexp.last_match).named_captures end elsif message.match?(YARN_PEER_DEP_ERROR_REGEX) message.scan(YARN_PEER_DEP_ERROR_REGEX) do - errors << Regexp.last_match.named_captures + errors << T.must(Regexp.last_match).named_captures end elsif message.match?(YARN_BERRY_PEER_DEP_ERROR_REGEX) message.scan(YARN_BERRY_PEER_DEP_ERROR_REGEX) do - errors << Regexp.last_match.named_captures + errors << T.must(Regexp.last_match).named_captures end elsif message.match?(YARN_BERRY_V4_PEER_DEP_ERROR_REGEX) message.scan(YARN_BERRY_V4_PEER_DEP_ERROR_REGEX) do - errors << Regexp.last_match.named_captures + errors << T.must(Regexp.last_match).named_captures end elsif message.match?(PNPM_PEER_DEP_ERROR_REGEX) message.scan(PNPM_PEER_DEP_ERROR_REGEX) do - captures = Regexp.last_match.named_captures - captures["requiring_dep"].tr!(" ", "@") + captures = T.must(Regexp.last_match).named_captures + T.must(captures["requiring_dep"]).tr!(" ", "@") errors << captures end else @@ -389,6 +396,7 @@ def handle_peer_dependency_errors(message) end errors end + # rubocop:enable Metrics/AbcSize def unmet_peer_dependencies peer_dependency_errors @@ -650,7 +658,7 @@ def version_install_arg(version:) git_source = dependency.requirements.find { |req| req[:source] && req[:source][:type] == "git" } if git_source - "#{dependency.name}@#{git_req[:source][:url]}##{version}" + "#{dependency.name}@#{git_source[:source][:url]}##{version}" else "#{dependency.name}@#{version}" end @@ -715,7 +723,7 @@ def requirement_class end def version_regex - version_class::VERSION_PATTERN + Dependabot::NpmAndYarn::Version::VERSION_PATTERN end end end diff --git a/pub/lib/dependabot/pub/update_checker.rb b/pub/lib/dependabot/pub/update_checker.rb index 5cfbbaaedb1c..7de08d618528 100644 --- a/pub/lib/dependabot/pub/update_checker.rb +++ b/pub/lib/dependabot/pub/update_checker.rb @@ -168,7 +168,7 @@ def resolve_requirements_update_strategy # go for RequirementsUpdateStrategy::BumpVersions. pubspec = T.must(dependency_files.find { |d| d.name == "pubspec.yaml" }) begin - parsed_pubspec = YAML.safe_load(T.must(pubspec.content), aliases: false) + parsed_pubspec = YAML.safe_load(T.must(pubspec.content), aliases: true) rescue ScriptError return RequirementsUpdateStrategy::BumpVersions end diff --git a/pub/spec/dependabot/pub/update_checker_spec.rb b/pub/spec/dependabot/pub/update_checker_spec.rb index 02d9a06cae70..83fbed46313f 100644 --- a/pub/spec/dependabot/pub/update_checker_spec.rb +++ b/pub/spec/dependabot/pub/update_checker_spec.rb @@ -791,4 +791,27 @@ ] end end + + context "loads a YAML file with alias" do + fixture = "spec/fixtures/projects/yaml_alias/" + alias_info_file = "pubspec_alias_true.yaml" + non_alias_info_file = "pubspec.yaml" + it "parses a alias contained YAML file with aliases: true" do + yaml_object = File.open(fixture + alias_info_file, "r") + data = yaml_object.read + expect { YAML.safe_load(data, aliases: true) }.not_to raise_error + end + + it "parses a alias contained YAML file with aliases: false" do + yaml_object = File.open(fixture + alias_info_file, "r") + data = yaml_object.read + expect { YAML.safe_load(data, aliases: false) }.to raise_error(Psych::AliasesNotEnabled) + end + + it "parses a no alias YAML file with aliases: true" do + yaml_object = File.open(fixture + non_alias_info_file, "r") + data = yaml_object.read + expect { YAML.safe_load(data, aliases: true) }.not_to raise_error + end + end end diff --git a/pub/spec/fixtures/projects/yaml_alias/pubspec.yaml b/pub/spec/fixtures/projects/yaml_alias/pubspec.yaml new file mode 100644 index 000000000000..1d34296f75d7 --- /dev/null +++ b/pub/spec/fixtures/projects/yaml_alias/pubspec.yaml @@ -0,0 +1,9 @@ +name: dependabot_testcase +environment: + sdk: '>=2.12.0 <3.0.0' +dependencies: + collection: ^1.14.13 # Locked to 1.14.13, can update with no unlock. + retry: ^2.0.0 # Can update with updated constraint, no further constraints. + protobuf: 1.1.4 # Can update with updated constraint, only together with fixnum to 2.0.0 or with fixnum and collection to 2.1.0. + fixnum: 0.10.11 + path: 1.8.0 # Already at latest diff --git a/pub/spec/fixtures/projects/yaml_alias/pubspec_alias_true.yaml b/pub/spec/fixtures/projects/yaml_alias/pubspec_alias_true.yaml new file mode 100644 index 000000000000..01494f9a9ede --- /dev/null +++ b/pub/spec/fixtures/projects/yaml_alias/pubspec_alias_true.yaml @@ -0,0 +1,16 @@ +default: &default + var1: info + var2: var5 + var3: 1 + +var4: + <<: *default + dir: ls/var4.info + +var5: + <<: *default + dir: ls/var5.info + +var6: + <<: *default + dir: ls/var6.info