dependabot-core 0.76.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (321) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +6408 -0
  3. data/LICENSE +37 -0
  4. data/README.md +115 -0
  5. data/helpers/elixir/bin/check_update.exs +92 -0
  6. data/helpers/elixir/bin/do_update.exs +39 -0
  7. data/helpers/elixir/bin/parse_deps.exs +103 -0
  8. data/helpers/elixir/bin/run.exs +76 -0
  9. data/helpers/elixir/mix.exs +21 -0
  10. data/helpers/elixir/mix.lock +3 -0
  11. data/helpers/go/Makefile +9 -0
  12. data/helpers/go/go.mod +9 -0
  13. data/helpers/go/go.sum +5 -0
  14. data/helpers/go/importresolver/main.go +34 -0
  15. data/helpers/go/main.go +77 -0
  16. data/helpers/go/updatechecker/main.go +107 -0
  17. data/helpers/go/updater/go.mod +3 -0
  18. data/helpers/go/updater/go.sum +2 -0
  19. data/helpers/go/updater/helpers.go +57 -0
  20. data/helpers/go/updater/main.go +48 -0
  21. data/helpers/npm/.agignore +1 -0
  22. data/helpers/npm/.envrc +2 -0
  23. data/helpers/npm/.eslintrc +14 -0
  24. data/helpers/npm/.nvimrc +7 -0
  25. data/helpers/npm/bin/run.js +34 -0
  26. data/helpers/npm/lib/helpers.js +25 -0
  27. data/helpers/npm/lib/peer-dependency-checker.js +102 -0
  28. data/helpers/npm/lib/subdependency-updater.js +48 -0
  29. data/helpers/npm/lib/updater.js +95 -0
  30. data/helpers/npm/package.json +17 -0
  31. data/helpers/npm/test/fixtures/npm-left-pad.json +1 -0
  32. data/helpers/npm/test/fixtures/updater/original/package-lock.json +16 -0
  33. data/helpers/npm/test/fixtures/updater/original/package.json +9 -0
  34. data/helpers/npm/test/fixtures/updater/updated/package-lock.json +16 -0
  35. data/helpers/npm/test/helpers.js +7 -0
  36. data/helpers/npm/test/updater.test.js +50 -0
  37. data/helpers/npm/yarn.lock +6120 -0
  38. data/helpers/php/.php_cs +34 -0
  39. data/helpers/php/bin/run.php +57 -0
  40. data/helpers/php/composer.json +14 -0
  41. data/helpers/php/composer.lock +1521 -0
  42. data/helpers/php/composer.phar +0 -0
  43. data/helpers/php/setup.sh +4 -0
  44. data/helpers/php/src/DependabotInstallationManager.php +61 -0
  45. data/helpers/php/src/DependabotPluginManager.php +23 -0
  46. data/helpers/php/src/ExceptionIO.php +25 -0
  47. data/helpers/php/src/Hasher.php +21 -0
  48. data/helpers/php/src/UpdateChecker.php +123 -0
  49. data/helpers/php/src/Updater.php +97 -0
  50. data/helpers/python/lib/__init__.py +0 -0
  51. data/helpers/python/lib/hasher.py +23 -0
  52. data/helpers/python/lib/parser.py +130 -0
  53. data/helpers/python/requirements.txt +9 -0
  54. data/helpers/python/run.py +18 -0
  55. data/helpers/test/run.rb +15 -0
  56. data/helpers/utils/git-credential-store-immutable +10 -0
  57. data/helpers/yarn/.agignore +1 -0
  58. data/helpers/yarn/.envrc +2 -0
  59. data/helpers/yarn/.eslintrc +14 -0
  60. data/helpers/yarn/.nvimrc +7 -0
  61. data/helpers/yarn/bin/run.js +36 -0
  62. data/helpers/yarn/lib/fix-duplicates.js +53 -0
  63. data/helpers/yarn/lib/helpers.js +5 -0
  64. data/helpers/yarn/lib/lockfile-parser.js +21 -0
  65. data/helpers/yarn/lib/peer-dependency-checker.js +130 -0
  66. data/helpers/yarn/lib/replace-lockfile-declaration.js +45 -0
  67. data/helpers/yarn/lib/subdependency-updater.js +69 -0
  68. data/helpers/yarn/lib/updater.js +254 -0
  69. data/helpers/yarn/package.json +17 -0
  70. data/helpers/yarn/test/fixtures/updater/original/package.json +6 -0
  71. data/helpers/yarn/test/fixtures/updater/original/yarn.lock +11 -0
  72. data/helpers/yarn/test/fixtures/updater/updated/yarn.lock +12 -0
  73. data/helpers/yarn/test/fixtures/updater/with-version-comments/package.json +5 -0
  74. data/helpers/yarn/test/fixtures/updater/with-version-comments/yarn.lock +13 -0
  75. data/helpers/yarn/test/fixtures/yarnpkg-is-positive.json +1 -0
  76. data/helpers/yarn/test/fixtures/yarnpkg-left-pad.json +1 -0
  77. data/helpers/yarn/test/helpers.js +7 -0
  78. data/helpers/yarn/test/updater.test.js +93 -0
  79. data/helpers/yarn/yarn.lock +4912 -0
  80. data/lib/bundler_definition_bundler_version_patch.rb +15 -0
  81. data/lib/bundler_definition_ruby_version_patch.rb +14 -0
  82. data/lib/bundler_git_source_patch.rb +27 -0
  83. data/lib/dependabot.rb +4 -0
  84. data/lib/dependabot/clients/bitbucket.rb +101 -0
  85. data/lib/dependabot/clients/github_with_retries.rb +117 -0
  86. data/lib/dependabot/clients/gitlab.rb +72 -0
  87. data/lib/dependabot/dependency.rb +118 -0
  88. data/lib/dependabot/dependency_file.rb +54 -0
  89. data/lib/dependabot/errors.rb +179 -0
  90. data/lib/dependabot/file_fetchers.rb +48 -0
  91. data/lib/dependabot/file_fetchers/README.md +65 -0
  92. data/lib/dependabot/file_fetchers/base.rb +302 -0
  93. data/lib/dependabot/file_fetchers/docker/docker.rb +40 -0
  94. data/lib/dependabot/file_fetchers/dotnet/nuget.rb +215 -0
  95. data/lib/dependabot/file_fetchers/dotnet/nuget/import_paths_finder.rb +51 -0
  96. data/lib/dependabot/file_fetchers/dotnet/nuget/sln_project_paths_finder.rb +55 -0
  97. data/lib/dependabot/file_fetchers/elixir/hex.rb +78 -0
  98. data/lib/dependabot/file_fetchers/elm/elm_package.rb +52 -0
  99. data/lib/dependabot/file_fetchers/git/submodules.rb +73 -0
  100. data/lib/dependabot/file_fetchers/go/dep.rb +69 -0
  101. data/lib/dependabot/file_fetchers/go/modules.rb +64 -0
  102. data/lib/dependabot/file_fetchers/java/gradle.rb +56 -0
  103. data/lib/dependabot/file_fetchers/java/gradle/settings_file_parser.rb +66 -0
  104. data/lib/dependabot/file_fetchers/java/maven.rb +127 -0
  105. data/lib/dependabot/file_fetchers/java_script/npm_and_yarn.rb +330 -0
  106. data/lib/dependabot/file_fetchers/java_script/npm_and_yarn/path_dependency_builder.rb +107 -0
  107. data/lib/dependabot/file_fetchers/php/composer.rb +131 -0
  108. data/lib/dependabot/file_fetchers/python/pip.rb +305 -0
  109. data/lib/dependabot/file_fetchers/ruby/bundler.rb +185 -0
  110. data/lib/dependabot/file_fetchers/ruby/bundler/child_gemfile_finder.rb +70 -0
  111. data/lib/dependabot/file_fetchers/ruby/bundler/path_gemspec_finder.rb +114 -0
  112. data/lib/dependabot/file_fetchers/ruby/bundler/require_relative_finder.rb +67 -0
  113. data/lib/dependabot/file_fetchers/rust/cargo.rb +240 -0
  114. data/lib/dependabot/file_parsers.rb +48 -0
  115. data/lib/dependabot/file_parsers/README.md +45 -0
  116. data/lib/dependabot/file_parsers/base.rb +31 -0
  117. data/lib/dependabot/file_parsers/base/dependency_set.rb +77 -0
  118. data/lib/dependabot/file_parsers/docker/docker.rb +164 -0
  119. data/lib/dependabot/file_parsers/dotnet/nuget.rb +85 -0
  120. data/lib/dependabot/file_parsers/dotnet/nuget/packages_config_parser.rb +65 -0
  121. data/lib/dependabot/file_parsers/dotnet/nuget/project_file_parser.rb +156 -0
  122. data/lib/dependabot/file_parsers/dotnet/nuget/property_value_finder.rb +131 -0
  123. data/lib/dependabot/file_parsers/elixir/hex.rb +134 -0
  124. data/lib/dependabot/file_parsers/elm/elm_package.rb +136 -0
  125. data/lib/dependabot/file_parsers/git/submodules.rb +69 -0
  126. data/lib/dependabot/file_parsers/go/dep.rb +163 -0
  127. data/lib/dependabot/file_parsers/go/modules.rb +34 -0
  128. data/lib/dependabot/file_parsers/go/modules/go_mod_parser.rb +134 -0
  129. data/lib/dependabot/file_parsers/java/gradle.rb +236 -0
  130. data/lib/dependabot/file_parsers/java/gradle/property_value_finder.rb +90 -0
  131. data/lib/dependabot/file_parsers/java/gradle/repositories_finder.rb +145 -0
  132. data/lib/dependabot/file_parsers/java/maven.rb +252 -0
  133. data/lib/dependabot/file_parsers/java/maven/property_value_finder.rb +166 -0
  134. data/lib/dependabot/file_parsers/java/maven/repositories_finder.rb +188 -0
  135. data/lib/dependabot/file_parsers/java_script/npm_and_yarn.rb +394 -0
  136. data/lib/dependabot/file_parsers/php/composer.rb +177 -0
  137. data/lib/dependabot/file_parsers/python/pip.rb +223 -0
  138. data/lib/dependabot/file_parsers/python/pip/pipfile_files_parser.rb +154 -0
  139. data/lib/dependabot/file_parsers/python/pip/poetry_files_parser.rb +141 -0
  140. data/lib/dependabot/file_parsers/python/pip/setup_file_parser.rb +160 -0
  141. data/lib/dependabot/file_parsers/ruby/bundler.rb +295 -0
  142. data/lib/dependabot/file_parsers/ruby/bundler/file_preparer.rb +85 -0
  143. data/lib/dependabot/file_parsers/ruby/bundler/gemfile_checker.rb +48 -0
  144. data/lib/dependabot/file_parsers/rust/cargo.rb +213 -0
  145. data/lib/dependabot/file_updaters.rb +48 -0
  146. data/lib/dependabot/file_updaters/README.md +58 -0
  147. data/lib/dependabot/file_updaters/base.rb +52 -0
  148. data/lib/dependabot/file_updaters/docker/docker.rb +133 -0
  149. data/lib/dependabot/file_updaters/dotnet/nuget.rb +151 -0
  150. data/lib/dependabot/file_updaters/dotnet/nuget/packages_config_declaration_finder.rb +69 -0
  151. data/lib/dependabot/file_updaters/dotnet/nuget/project_file_declaration_finder.rb +78 -0
  152. data/lib/dependabot/file_updaters/dotnet/nuget/property_value_updater.rb +64 -0
  153. data/lib/dependabot/file_updaters/elixir/hex.rb +71 -0
  154. data/lib/dependabot/file_updaters/elixir/hex/lockfile_updater.rb +147 -0
  155. data/lib/dependabot/file_updaters/elixir/hex/mixfile_git_pin_updater.rb +53 -0
  156. data/lib/dependabot/file_updaters/elixir/hex/mixfile_requirement_updater.rb +74 -0
  157. data/lib/dependabot/file_updaters/elixir/hex/mixfile_sanitizer.rb +28 -0
  158. data/lib/dependabot/file_updaters/elixir/hex/mixfile_updater.rb +98 -0
  159. data/lib/dependabot/file_updaters/elm/elm_package.rb +79 -0
  160. data/lib/dependabot/file_updaters/elm/elm_package/elm_json_updater.rb +69 -0
  161. data/lib/dependabot/file_updaters/elm/elm_package/elm_package_updater.rb +69 -0
  162. data/lib/dependabot/file_updaters/git/submodules.rb +38 -0
  163. data/lib/dependabot/file_updaters/go/dep.rb +77 -0
  164. data/lib/dependabot/file_updaters/go/dep/lockfile_updater.rb +219 -0
  165. data/lib/dependabot/file_updaters/go/dep/manifest_updater.rb +155 -0
  166. data/lib/dependabot/file_updaters/go/modules.rb +71 -0
  167. data/lib/dependabot/file_updaters/go/modules/go_mod_updater.rb +81 -0
  168. data/lib/dependabot/file_updaters/java/gradle.rb +176 -0
  169. data/lib/dependabot/file_updaters/java/gradle/dependency_set_updater.rb +66 -0
  170. data/lib/dependabot/file_updaters/java/gradle/property_value_updater.rb +58 -0
  171. data/lib/dependabot/file_updaters/java/maven.rb +155 -0
  172. data/lib/dependabot/file_updaters/java/maven/declaration_finder.rb +132 -0
  173. data/lib/dependabot/file_updaters/java/maven/property_value_updater.rb +61 -0
  174. data/lib/dependabot/file_updaters/java_script/npm_and_yarn.rb +159 -0
  175. data/lib/dependabot/file_updaters/java_script/npm_and_yarn/npm_lockfile_updater.rb +532 -0
  176. data/lib/dependabot/file_updaters/java_script/npm_and_yarn/npmrc_builder.rb +191 -0
  177. data/lib/dependabot/file_updaters/java_script/npm_and_yarn/package_json_preparer.rb +91 -0
  178. data/lib/dependabot/file_updaters/java_script/npm_and_yarn/package_json_updater.rb +220 -0
  179. data/lib/dependabot/file_updaters/java_script/npm_and_yarn/yarn_lockfile_updater.rb +475 -0
  180. data/lib/dependabot/file_updaters/php/composer.rb +78 -0
  181. data/lib/dependabot/file_updaters/php/composer/lockfile_updater.rb +264 -0
  182. data/lib/dependabot/file_updaters/php/composer/manifest_updater.rb +70 -0
  183. data/lib/dependabot/file_updaters/python/pip.rb +147 -0
  184. data/lib/dependabot/file_updaters/python/pip/pip_compile_file_updater.rb +363 -0
  185. data/lib/dependabot/file_updaters/python/pip/pipfile_file_updater.rb +397 -0
  186. data/lib/dependabot/file_updaters/python/pip/pipfile_preparer.rb +125 -0
  187. data/lib/dependabot/file_updaters/python/pip/poetry_file_updater.rb +289 -0
  188. data/lib/dependabot/file_updaters/python/pip/pyproject_preparer.rb +105 -0
  189. data/lib/dependabot/file_updaters/python/pip/requirement_file_updater.rb +166 -0
  190. data/lib/dependabot/file_updaters/python/pip/requirement_replacer.rb +95 -0
  191. data/lib/dependabot/file_updaters/python/pip/setup_file_sanitizer.rb +91 -0
  192. data/lib/dependabot/file_updaters/ruby/bundler.rb +121 -0
  193. data/lib/dependabot/file_updaters/ruby/bundler/gemfile_updater.rb +116 -0
  194. data/lib/dependabot/file_updaters/ruby/bundler/gemspec_dependency_name_finder.rb +52 -0
  195. data/lib/dependabot/file_updaters/ruby/bundler/gemspec_sanitizer.rb +298 -0
  196. data/lib/dependabot/file_updaters/ruby/bundler/gemspec_updater.rb +64 -0
  197. data/lib/dependabot/file_updaters/ruby/bundler/git_pin_replacer.rb +80 -0
  198. data/lib/dependabot/file_updaters/ruby/bundler/git_source_remover.rb +102 -0
  199. data/lib/dependabot/file_updaters/ruby/bundler/lockfile_updater.rb +384 -0
  200. data/lib/dependabot/file_updaters/ruby/bundler/requirement_replacer.rb +188 -0
  201. data/lib/dependabot/file_updaters/rust/cargo.rb +83 -0
  202. data/lib/dependabot/file_updaters/rust/cargo/lockfile_updater.rb +251 -0
  203. data/lib/dependabot/file_updaters/rust/cargo/manifest_updater.rb +162 -0
  204. data/lib/dependabot/git_commit_checker.rb +412 -0
  205. data/lib/dependabot/metadata_finders.rb +46 -0
  206. data/lib/dependabot/metadata_finders/README.md +53 -0
  207. data/lib/dependabot/metadata_finders/base.rb +117 -0
  208. data/lib/dependabot/metadata_finders/base/changelog_finder.rb +317 -0
  209. data/lib/dependabot/metadata_finders/base/changelog_pruner.rb +177 -0
  210. data/lib/dependabot/metadata_finders/base/commits_finder.rb +217 -0
  211. data/lib/dependabot/metadata_finders/base/release_finder.rb +251 -0
  212. data/lib/dependabot/metadata_finders/docker/docker.rb +18 -0
  213. data/lib/dependabot/metadata_finders/dotnet/nuget.rb +116 -0
  214. data/lib/dependabot/metadata_finders/elixir/hex.rb +69 -0
  215. data/lib/dependabot/metadata_finders/elm/elm_package.rb +22 -0
  216. data/lib/dependabot/metadata_finders/git/submodules.rb +20 -0
  217. data/lib/dependabot/metadata_finders/go/dep.rb +56 -0
  218. data/lib/dependabot/metadata_finders/java/maven.rb +173 -0
  219. data/lib/dependabot/metadata_finders/java_script/npm_and_yarn.rb +215 -0
  220. data/lib/dependabot/metadata_finders/php/composer.rb +66 -0
  221. data/lib/dependabot/metadata_finders/python/pip.rb +120 -0
  222. data/lib/dependabot/metadata_finders/ruby/bundler.rb +150 -0
  223. data/lib/dependabot/metadata_finders/rust/cargo.rb +64 -0
  224. data/lib/dependabot/pull_request_creator.rb +151 -0
  225. data/lib/dependabot/pull_request_creator/branch_namer.rb +170 -0
  226. data/lib/dependabot/pull_request_creator/commit_signer.rb +63 -0
  227. data/lib/dependabot/pull_request_creator/github.rb +233 -0
  228. data/lib/dependabot/pull_request_creator/gitlab.rb +122 -0
  229. data/lib/dependabot/pull_request_creator/labeler.rb +361 -0
  230. data/lib/dependabot/pull_request_creator/message_builder.rb +888 -0
  231. data/lib/dependabot/pull_request_updater.rb +43 -0
  232. data/lib/dependabot/pull_request_updater/github.rb +151 -0
  233. data/lib/dependabot/shared_helpers.rb +201 -0
  234. data/lib/dependabot/source.rb +120 -0
  235. data/lib/dependabot/update_checkers.rb +48 -0
  236. data/lib/dependabot/update_checkers/README.md +67 -0
  237. data/lib/dependabot/update_checkers/base.rb +220 -0
  238. data/lib/dependabot/update_checkers/docker/docker.rb +290 -0
  239. data/lib/dependabot/update_checkers/dotnet/nuget.rb +127 -0
  240. data/lib/dependabot/update_checkers/dotnet/nuget/property_updater.rb +97 -0
  241. data/lib/dependabot/update_checkers/dotnet/nuget/repository_finder.rb +232 -0
  242. data/lib/dependabot/update_checkers/dotnet/nuget/requirements_updater.rb +81 -0
  243. data/lib/dependabot/update_checkers/dotnet/nuget/version_finder.rb +231 -0
  244. data/lib/dependabot/update_checkers/elixir/hex.rb +274 -0
  245. data/lib/dependabot/update_checkers/elixir/hex/file_preparer.rb +193 -0
  246. data/lib/dependabot/update_checkers/elixir/hex/requirements_updater.rb +177 -0
  247. data/lib/dependabot/update_checkers/elixir/hex/version_resolver.rb +175 -0
  248. data/lib/dependabot/update_checkers/elm/elm_package.rb +126 -0
  249. data/lib/dependabot/update_checkers/elm/elm_package/cli_parser.rb +33 -0
  250. data/lib/dependabot/update_checkers/elm/elm_package/elm_18_version_resolver.rb +234 -0
  251. data/lib/dependabot/update_checkers/elm/elm_package/elm_19_version_resolver.rb +198 -0
  252. data/lib/dependabot/update_checkers/elm/elm_package/requirements_updater.rb +75 -0
  253. data/lib/dependabot/update_checkers/git/submodules.rb +52 -0
  254. data/lib/dependabot/update_checkers/go/dep.rb +311 -0
  255. data/lib/dependabot/update_checkers/go/dep/file_preparer.rb +221 -0
  256. data/lib/dependabot/update_checkers/go/dep/latest_version_finder.rb +169 -0
  257. data/lib/dependabot/update_checkers/go/dep/requirements_updater.rb +223 -0
  258. data/lib/dependabot/update_checkers/go/dep/version_resolver.rb +164 -0
  259. data/lib/dependabot/update_checkers/go/modules.rb +112 -0
  260. data/lib/dependabot/update_checkers/java/gradle.rb +148 -0
  261. data/lib/dependabot/update_checkers/java/gradle/multi_dependency_updater.rb +105 -0
  262. data/lib/dependabot/update_checkers/java/gradle/version_finder.rb +183 -0
  263. data/lib/dependabot/update_checkers/java/maven.rb +159 -0
  264. data/lib/dependabot/update_checkers/java/maven/property_updater.rb +127 -0
  265. data/lib/dependabot/update_checkers/java/maven/requirements_updater.rb +92 -0
  266. data/lib/dependabot/update_checkers/java/maven/version_finder.rb +225 -0
  267. data/lib/dependabot/update_checkers/java_script/npm_and_yarn.rb +280 -0
  268. data/lib/dependabot/update_checkers/java_script/npm_and_yarn/latest_version_finder.rb +342 -0
  269. data/lib/dependabot/update_checkers/java_script/npm_and_yarn/library_detector.rb +69 -0
  270. data/lib/dependabot/update_checkers/java_script/npm_and_yarn/registry_finder.rb +226 -0
  271. data/lib/dependabot/update_checkers/java_script/npm_and_yarn/requirements_updater.rb +197 -0
  272. data/lib/dependabot/update_checkers/java_script/npm_and_yarn/subdependency_version_resolver.rb +228 -0
  273. data/lib/dependabot/update_checkers/java_script/npm_and_yarn/version_resolver.rb +452 -0
  274. data/lib/dependabot/update_checkers/php/composer.rb +165 -0
  275. data/lib/dependabot/update_checkers/php/composer/requirements_updater.rb +243 -0
  276. data/lib/dependabot/update_checkers/php/composer/version_resolver.rb +203 -0
  277. data/lib/dependabot/update_checkers/python/pip.rb +227 -0
  278. data/lib/dependabot/update_checkers/python/pip/latest_version_finder.rb +252 -0
  279. data/lib/dependabot/update_checkers/python/pip/pip_compile_version_resolver.rb +380 -0
  280. data/lib/dependabot/update_checkers/python/pip/pipfile_version_resolver.rb +559 -0
  281. data/lib/dependabot/update_checkers/python/pip/poetry_version_resolver.rb +300 -0
  282. data/lib/dependabot/update_checkers/python/pip/requirements_updater.rb +367 -0
  283. data/lib/dependabot/update_checkers/ruby/bundler.rb +324 -0
  284. data/lib/dependabot/update_checkers/ruby/bundler/file_preparer.rb +278 -0
  285. data/lib/dependabot/update_checkers/ruby/bundler/force_updater.rb +261 -0
  286. data/lib/dependabot/update_checkers/ruby/bundler/latest_version_finder.rb +169 -0
  287. data/lib/dependabot/update_checkers/ruby/bundler/requirements_updater.rb +264 -0
  288. data/lib/dependabot/update_checkers/ruby/bundler/ruby_requirement_setter.rb +115 -0
  289. data/lib/dependabot/update_checkers/ruby/bundler/shared_bundler_helpers.rb +243 -0
  290. data/lib/dependabot/update_checkers/ruby/bundler/version_resolver.rb +255 -0
  291. data/lib/dependabot/update_checkers/rust/cargo.rb +282 -0
  292. data/lib/dependabot/update_checkers/rust/cargo/file_preparer.rb +202 -0
  293. data/lib/dependabot/update_checkers/rust/cargo/requirements_updater.rb +175 -0
  294. data/lib/dependabot/update_checkers/rust/cargo/version_resolver.rb +242 -0
  295. data/lib/dependabot/utils.rb +84 -0
  296. data/lib/dependabot/utils/docker/credentials_finder.rb +65 -0
  297. data/lib/dependabot/utils/dotnet/requirement.rb +90 -0
  298. data/lib/dependabot/utils/dotnet/version.rb +22 -0
  299. data/lib/dependabot/utils/elixir/requirement.rb +53 -0
  300. data/lib/dependabot/utils/elixir/version.rb +59 -0
  301. data/lib/dependabot/utils/elm/requirement.rb +92 -0
  302. data/lib/dependabot/utils/elm/version.rb +19 -0
  303. data/lib/dependabot/utils/go/path_converter.rb +74 -0
  304. data/lib/dependabot/utils/go/requirement.rb +152 -0
  305. data/lib/dependabot/utils/go/shared_helper.rb +20 -0
  306. data/lib/dependabot/utils/go/version.rb +40 -0
  307. data/lib/dependabot/utils/java/requirement.rb +110 -0
  308. data/lib/dependabot/utils/java/version.rb +179 -0
  309. data/lib/dependabot/utils/java_script/requirement.rb +117 -0
  310. data/lib/dependabot/utils/java_script/version.rb +30 -0
  311. data/lib/dependabot/utils/php/requirement.rb +97 -0
  312. data/lib/dependabot/utils/php/version.rb +22 -0
  313. data/lib/dependabot/utils/python/requirement.rb +130 -0
  314. data/lib/dependabot/utils/python/version.rb +88 -0
  315. data/lib/dependabot/utils/ruby/requirement.rb +26 -0
  316. data/lib/dependabot/utils/rust/requirement.rb +108 -0
  317. data/lib/dependabot/utils/rust/version.rb +32 -0
  318. data/lib/dependabot/version.rb +5 -0
  319. data/lib/python_requirement_parser.rb +33 -0
  320. data/lib/python_versions.rb +21 -0
  321. metadata +641 -0
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+
5
+ module Dependabot
6
+ class DependencyFile
7
+ attr_accessor :name, :content, :directory, :type, :support_file
8
+
9
+ def initialize(name:, content:, directory: "/", type: "file",
10
+ support_file: false)
11
+ @name = name
12
+ @content = content
13
+ @directory = clean_directory(directory)
14
+ @type = type
15
+ @support_file = support_file
16
+ end
17
+
18
+ def to_h
19
+ {
20
+ "name" => name,
21
+ "content" => content,
22
+ "directory" => directory,
23
+ "type" => type
24
+ }
25
+ end
26
+
27
+ def path
28
+ Pathname.new(File.join(directory, name)).cleanpath.to_path
29
+ end
30
+
31
+ def ==(other)
32
+ other.instance_of?(self.class) && to_h == other.to_h
33
+ end
34
+
35
+ def hash
36
+ to_h.hash
37
+ end
38
+
39
+ def eql?(other)
40
+ self.==(other)
41
+ end
42
+
43
+ def support_file?
44
+ @support_file
45
+ end
46
+
47
+ private
48
+
49
+ def clean_directory(directory)
50
+ # Directory should always start with a `/`
51
+ directory.sub(%r{^/*}, "/")
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,179 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dependabot/shared_helpers"
4
+
5
+ module Dependabot
6
+ class DependabotError < StandardError
7
+ def initialize(msg = nil)
8
+ msg = sanitize_message(msg)
9
+ super(msg)
10
+ end
11
+
12
+ private
13
+
14
+ def sanitize_message(message)
15
+ return unless message
16
+
17
+ path_regex =
18
+ Regexp.escape(SharedHelpers::BUMP_TMP_DIR_PATH) + "\/" +
19
+ Regexp.escape(SharedHelpers::BUMP_TMP_FILE_PREFIX) + "[^/]*"
20
+
21
+ message.gsub(/#{path_regex}/, "dependabot_tmp_dir")
22
+ end
23
+ end
24
+
25
+ class OutOfMemory < DependabotError; end
26
+
27
+ #####################
28
+ # Repo leval errors #
29
+ #####################
30
+
31
+ class BranchNotFound < DependabotError
32
+ attr_reader :branch_name
33
+
34
+ def initialize(branch_name, msg = nil)
35
+ @branch_name = branch_name
36
+ msg = sanitize_message(msg)
37
+ super(msg)
38
+ end
39
+ end
40
+
41
+ class RepoNotFound < DependabotError
42
+ attr_reader :source
43
+
44
+ def initialize(source, msg = nil)
45
+ @source = source
46
+ super(msg)
47
+ end
48
+ end
49
+
50
+ #####################
51
+ # File level errors #
52
+ #####################
53
+
54
+ class DependencyFileNotFound < DependabotError
55
+ attr_reader :file_path
56
+
57
+ def initialize(file_path, msg = nil)
58
+ @file_path = file_path
59
+ super(msg)
60
+ end
61
+
62
+ def file_name
63
+ file_path.split("/").last
64
+ end
65
+
66
+ def directory
67
+ # Directory should always start with a `/`
68
+ file_path.split("/")[0..-2].join("/").sub(%r{^/*}, "/")
69
+ end
70
+ end
71
+
72
+ class DependencyFileNotParseable < DependabotError
73
+ attr_reader :file_path
74
+
75
+ def initialize(file_path, msg = nil)
76
+ @file_path = file_path
77
+ super(msg)
78
+ end
79
+
80
+ def file_name
81
+ file_path.split("/").last
82
+ end
83
+
84
+ def directory
85
+ # Directory should always start with a `/`
86
+ file_path.split("/")[0..-2].join("/").sub(%r{^/*}, "/")
87
+ end
88
+ end
89
+
90
+ class DependencyFileNotEvaluatable < DependabotError; end
91
+ class DependencyFileNotResolvable < DependabotError; end
92
+
93
+ #######################
94
+ # Source level errors #
95
+ #######################
96
+
97
+ class PrivateSourceAuthenticationFailure < DependabotError
98
+ attr_reader :source
99
+
100
+ def initialize(source)
101
+ @source = source
102
+ msg = "The following source could not be reached as it requires "\
103
+ "authentication (and any provided details were invalid or lacked "\
104
+ "the required permissions): #{source}"
105
+ super(msg)
106
+ end
107
+ end
108
+
109
+ class PrivateSourceTimedOut < DependabotError
110
+ attr_reader :source
111
+
112
+ def initialize(source)
113
+ @source = source
114
+ super("The following source timed out: #{source}")
115
+ end
116
+ end
117
+
118
+ class PrivateSourceCertificateFailure < DependabotError
119
+ attr_reader :source
120
+
121
+ def initialize(source)
122
+ @source = source
123
+ super("Could not verify the SSL certificate for #{source}")
124
+ end
125
+ end
126
+
127
+ class MissingEnvironmentVariable < DependabotError
128
+ attr_reader :environment_variable
129
+
130
+ def initialize(environment_variable)
131
+ @environment_variable = environment_variable
132
+ super("Missing environment variable #{environment_variable}")
133
+ end
134
+ end
135
+
136
+ # Useful for JS file updaters, where the registry API sometimes returns
137
+ # different results to the actual update process
138
+ class InconsistentRegistryResponse < DependabotError; end
139
+
140
+ ###########################
141
+ # Dependency level errors #
142
+ ###########################
143
+
144
+ class GitDependenciesNotReachable < DependabotError
145
+ attr_reader :dependency_urls
146
+
147
+ def initialize(*dependency_urls)
148
+ @dependency_urls =
149
+ dependency_urls.flatten.map { |uri| uri.gsub(/x-access-token.*?@/, "") }
150
+
151
+ msg = "The following git URLs could not be retrieved: "\
152
+ "#{dependency_urls.join(', ')}"
153
+ super(msg)
154
+ end
155
+ end
156
+
157
+ class GitDependencyReferenceNotFound < DependabotError
158
+ attr_reader :dependency
159
+
160
+ def initialize(dependency)
161
+ @dependency = dependency
162
+
163
+ msg = "The branch or reference specified for #{dependency} could not "\
164
+ "be retrieved"
165
+ super(msg)
166
+ end
167
+ end
168
+
169
+ class PathDependenciesNotReachable < DependabotError
170
+ attr_reader :dependencies
171
+
172
+ def initialize(*dependencies)
173
+ @dependencies = dependencies.flatten
174
+ msg = "The following path based dependencies could not be retrieved: "\
175
+ "#{dependencies.join(', ')}"
176
+ super(msg)
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dependabot/file_fetchers/ruby/bundler"
4
+ require "dependabot/file_fetchers/python/pip"
5
+ require "dependabot/file_fetchers/java_script/npm_and_yarn"
6
+ require "dependabot/file_fetchers/java/maven"
7
+ require "dependabot/file_fetchers/java/gradle"
8
+ require "dependabot/file_fetchers/php/composer"
9
+ require "dependabot/file_fetchers/git/submodules"
10
+ require "dependabot/file_fetchers/docker/docker"
11
+ require "dependabot/file_fetchers/elixir/hex"
12
+ require "dependabot/file_fetchers/rust/cargo"
13
+ require "dependabot/file_fetchers/dotnet/nuget"
14
+ require "dependabot/file_fetchers/go/dep"
15
+ require "dependabot/file_fetchers/go/modules"
16
+ require "dependabot/file_fetchers/elm/elm_package"
17
+
18
+ module Dependabot
19
+ module FileFetchers
20
+ @file_fetchers = {
21
+ "bundler" => FileFetchers::Ruby::Bundler,
22
+ "npm_and_yarn" => FileFetchers::JavaScript::NpmAndYarn,
23
+ "maven" => FileFetchers::Java::Maven,
24
+ "gradle" => FileFetchers::Java::Gradle,
25
+ "pip" => FileFetchers::Python::Pip,
26
+ "composer" => FileFetchers::Php::Composer,
27
+ "submodules" => FileFetchers::Git::Submodules,
28
+ "docker" => FileFetchers::Docker::Docker,
29
+ "hex" => FileFetchers::Elixir::Hex,
30
+ "cargo" => FileFetchers::Rust::Cargo,
31
+ "nuget" => FileFetchers::Dotnet::Nuget,
32
+ "dep" => FileFetchers::Go::Dep,
33
+ "go_modules" => FileFetchers::Go::Modules,
34
+ "elm-package" => FileFetchers::Elm::ElmPackage
35
+ }
36
+
37
+ def self.for_package_manager(package_manager)
38
+ file_fetcher = @file_fetchers[package_manager]
39
+ return file_fetcher if file_fetcher
40
+
41
+ raise "Unsupported package_manager #{package_manager}"
42
+ end
43
+
44
+ def self.register(package_manager, file_fetcher)
45
+ @file_fetchers[package_manager] = file_fetcher
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,65 @@
1
+ # File fetchers
2
+
3
+ File fetchers are used to fetch the relevant dependency files for a project
4
+ (e.g., the `Gemfile` and `Gemfile.lock`). They are also responsible for checking
5
+ whether a repo has an admissable set of requirement files.
6
+
7
+ There is a `Dependabot::FileFetchers` class for each language Dependabot
8
+ supports.
9
+
10
+ ## Public API
11
+
12
+ Each `Dependabot::FileFetchers` class implements the following methods:
13
+
14
+ | Method | Description |
15
+ |----------------------------------|-----------------------------------------------------------------------------------------------|
16
+ | `.required_files_in?` | Checks an array of filenames (string) and returns a boolean describing whether the language-specific dependency files required for an update run are present. |
17
+ | `.required_files_message` | Returns a static error message which can be displayed to a user if `required_files_in?` returns false. |
18
+ | `#files` | Fetches the language-specific dependency files for the repo this instance was created with. Returns an array of `Dependabot::DependencyFile` instances. |
19
+ | `#commit` | Returns the commit SHA-1 hash at the time the dependency files were fetched. If called before `files`, the returned value will be used in subsequent calls to `files`. |
20
+
21
+
22
+ An integration might look as follows:
23
+
24
+ ```ruby
25
+ require 'octokit'
26
+ require 'dependabot/file_fetchers'
27
+ require 'dependabot/source'
28
+
29
+ target_repo_name = 'dependabot/dependabot-core'
30
+ source = Dependabot::Source.new(provider: 'github', repo: target_repo_name)
31
+
32
+ client = Octokit::Client.new
33
+ fetcher_class = Dependabot::FileFetchers::Ruby::Bundler
34
+ filenames = client.contents(target_repo_name).map(&:name)
35
+
36
+ unless fetcher_class.required_files_in?(filenames)
37
+ raise fetcher_class.required_files_message
38
+ end
39
+
40
+ fetcher = fetcher_class.new(source: source, credentials: [])
41
+
42
+ puts "Fetched #{fetcher.files.map(&:name)}, at commit SHA-1 '#{fetcher.commit}'"
43
+ ```
44
+
45
+ ## Writing a file fetcher for a new language
46
+
47
+ All new file fetchers should inherit from `Dependabot::FileFetchers::Base` and
48
+ implement the following methods:
49
+
50
+ | Method | Description |
51
+ |----------------------------------|-----------------------------------------------------------------------------------------------|
52
+ | `.required_files_in?` | See Public API section. |
53
+ | `.required_files_message` | See Public API section. |
54
+ | `#fetch_files` | Private method to fetch the required files from GitHub. For each required file, you can use the `fetch_file_from_host(filename)` method from `Dependabot::FileFetchers::Base` to do the fetching. |
55
+
56
+ To ensure the above are implemented, you should include
57
+ `it_behaves_like "a dependency file fetcher"` in your specs for the new file
58
+ fetcher.
59
+
60
+ File fetchers tend to get complicated when the file requirements for an update
61
+ to run are non-trivial - for example, for Ruby we could accept
62
+ [`Gemfile`, `Gemfile.lock`] or [`Gemfile`, `example.gemspec`],
63
+ but not just [`Gemfile.lock`]. When adding a new lanugage, it's normally easiest
64
+ to pick a single case and implement it for all the update steps (parsing, update
65
+ checking, etc.). You can then return and add other cases later.
@@ -0,0 +1,302 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dependabot/dependency_file"
4
+ require "dependabot/source"
5
+ require "dependabot/errors"
6
+ require "dependabot/clients/github_with_retries"
7
+ require "dependabot/clients/bitbucket"
8
+ require "dependabot/clients/gitlab"
9
+ require "dependabot/shared_helpers"
10
+
11
+ module Dependabot
12
+ module FileFetchers
13
+ class Base
14
+ attr_reader :source, :credentials
15
+
16
+ def self.required_files_in?(_filename_array)
17
+ raise NotImplementedError
18
+ end
19
+
20
+ def self.required_files_message
21
+ raise NotImplementedError
22
+ end
23
+
24
+ def initialize(source:, credentials:)
25
+ @source = source
26
+ @credentials = credentials
27
+
28
+ @submodule_directories = {}
29
+ end
30
+
31
+ def repo
32
+ source.repo
33
+ end
34
+
35
+ def directory
36
+ source.directory || "/"
37
+ end
38
+
39
+ def target_branch
40
+ source.branch
41
+ end
42
+
43
+ def files
44
+ @files ||= fetch_files
45
+ end
46
+
47
+ def commit
48
+ branch = target_branch || default_branch_for_repo
49
+
50
+ @commit ||= client_for_provider.fetch_commit(repo, branch)
51
+ rescue Octokit::NotFound, Gitlab::Error::NotFound,
52
+ Dependabot::Clients::Bitbucket::NotFound
53
+ raise Dependabot::BranchNotFound, branch
54
+ rescue Octokit::Conflict => error
55
+ raise unless error.message.include?("Repository is empty")
56
+ end
57
+
58
+ private
59
+
60
+ def client_for_provider
61
+ case source.provider
62
+ when "github"
63
+ github_client_for_source
64
+ when "gitlab"
65
+ gitlab_client
66
+ when "bitbucket"
67
+ bitbucket_client
68
+ else raise "Unsupported provider '#{source.provider}'."
69
+ end
70
+ end
71
+
72
+ def default_branch_for_repo
73
+ @default_branch_for_repo ||=
74
+ client_for_provider.fetch_default_branch(repo)
75
+ rescue Octokit::NotFound, Gitlab::Error::NotFound,
76
+ Dependabot::Clients::Bitbucket::NotFound
77
+ raise Dependabot::RepoNotFound, source
78
+ end
79
+
80
+ def fetch_file_if_present(filename)
81
+ dir = File.dirname(filename)
82
+ basename = File.basename(filename)
83
+ return unless repo_contents(dir: dir).map(&:name).include?(basename)
84
+
85
+ fetch_file_from_host(filename)
86
+ rescue Octokit::NotFound, Gitlab::Error::NotFound,
87
+ Dependabot::Clients::Bitbucket::NotFound
88
+ path = Pathname.new(File.join(directory, filename)).cleanpath.to_path
89
+ raise Dependabot::DependencyFileNotFound, path
90
+ end
91
+
92
+ def fetch_file_from_host(filename, type: "file")
93
+ path = Pathname.new(File.join(directory, filename)).cleanpath.to_path
94
+
95
+ DependencyFile.new(
96
+ name: Pathname.new(filename).cleanpath.to_path,
97
+ content: fetch_file_content(path),
98
+ directory: directory,
99
+ type: type
100
+ )
101
+ rescue Octokit::NotFound, Gitlab::Error::NotFound,
102
+ Dependabot::Clients::Bitbucket::NotFound
103
+ raise Dependabot::DependencyFileNotFound, path
104
+ end
105
+
106
+ def fetch_file_from_host_or_submodule(filename, type: "file")
107
+ fetch_file_from_host(filename, type: type)
108
+ rescue Dependabot::DependencyFileNotFound => error
109
+ begin
110
+ repo_contents(dir: File.dirname(filename))
111
+ rescue StandardError
112
+ raise error
113
+ end
114
+
115
+ fetch_file_from_host(filename, type: type)
116
+ end
117
+
118
+ def repo_contents(dir: ".", raise_errors: true)
119
+ path = Pathname.new(File.join(directory, dir)).
120
+ cleanpath.to_path.gsub(%r{^/*}, "")
121
+
122
+ # Don't fetch contents of repos nested in submodules
123
+ submods = @submodule_directories
124
+ if submods.keys.any? { |k| path.match?(%r{#{Regexp.quote(k)}(/|$)}) }
125
+ return []
126
+ end
127
+
128
+ @repo_contents ||= {}
129
+ @repo_contents[dir] ||=
130
+ case source.provider
131
+ when "github" then github_repo_contents(path)
132
+ when "gitlab" then gitlab_repo_contents(path)
133
+ when "bitbucket" then bitbucket_repo_contents(path)
134
+ else raise "Unsupported provider '#{source.provider}'."
135
+ end
136
+ rescue Octokit::NotFound, Gitlab::Error::NotFound,
137
+ Dependabot::Clients::Bitbucket::NotFound
138
+ raise if raise_errors
139
+
140
+ []
141
+ end
142
+
143
+ def github_repo_contents(path)
144
+ github_response = github_client_for_source.
145
+ contents(repo, path: path, ref: commit)
146
+
147
+ if github_response.respond_to?(:type) &&
148
+ github_response.type == "submodule"
149
+ @submodule_directories[path] = github_response
150
+
151
+ sub_source = Source.from_url(github_response.submodule_git_url)
152
+ github_response = github_client_for_source.
153
+ contents(sub_source.repo, ref: github_response.sha)
154
+ elsif github_response.respond_to?(:type)
155
+ raise Octokit::NotFound
156
+ end
157
+
158
+ github_response.map do |f|
159
+ OpenStruct.new(
160
+ name: f.name,
161
+ path: f.path,
162
+ type: f.type,
163
+ sha: f.sha,
164
+ size: f.size
165
+ )
166
+ end
167
+ end
168
+
169
+ def gitlab_repo_contents(path)
170
+ gitlab_client.
171
+ repo_tree(repo, path: path, ref_name: commit, per_page: 100).
172
+ map do |file|
173
+ OpenStruct.new(
174
+ name: file.name,
175
+ path: file.path,
176
+ type: file.type == "blob" ? "file" : file.type,
177
+ size: 0 # GitLab doesn't return file size
178
+ )
179
+ end
180
+ end
181
+
182
+ def bitbucket_repo_contents(path)
183
+ response = bitbucket_client.fetch_repo_contents(
184
+ repo,
185
+ commit,
186
+ path
187
+ )
188
+
189
+ response.map do |file|
190
+ type = case file.fetch("type")
191
+ when "commit_file" then "file"
192
+ when "commit_directory" then "dir"
193
+ else file.fetch("type")
194
+ end
195
+
196
+ OpenStruct.new(
197
+ name: File.basename(file.fetch("path")),
198
+ path: file.fetch("path"),
199
+ type: type,
200
+ size: file.fetch("size", 0)
201
+ )
202
+ end
203
+ end
204
+
205
+ def fetch_file_content(path)
206
+ path = path.gsub(%r{^/*}, "")
207
+ dir = Pathname.new(path).dirname.to_path.gsub(%r{^/*}, "")
208
+
209
+ if @submodule_directories.key?(dir)
210
+ return fetch_submodule_file_content(path)
211
+ end
212
+
213
+ case source.provider
214
+ when "github"
215
+ fetch_file_content_from_github(path, repo, commit)
216
+ when "gitlab"
217
+ tmp = gitlab_client.get_file(repo, path, commit).content
218
+ Base64.decode64(tmp).force_encoding("UTF-8").encode
219
+ when "bitbucket"
220
+ bitbucket_client.fetch_file_contents(repo, commit, path)
221
+ else raise "Unsupported provider '#{source.provider}'."
222
+ end
223
+ end
224
+
225
+ def fetch_submodule_file_content(path)
226
+ path = path.gsub(%r{^/*}, "")
227
+ dir = Pathname.new(path).dirname.to_path.gsub(%r{^/*}, "")
228
+ submodule = @submodule_directories[dir]
229
+
230
+ provider = Source.from_url(submodule.submodule_git_url).provider
231
+ repo = Source.from_url(submodule.submodule_git_url).repo
232
+ commit = submodule.sha
233
+ path = path.gsub("#{dir}/", "")
234
+
235
+ case provider
236
+ when "github"
237
+ fetch_file_content_from_github(path, repo, commit)
238
+ when "gitlab"
239
+ tmp = gitlab_client.get_file(repo, path, commit).content
240
+ Base64.decode64(tmp).force_encoding("UTF-8").encode
241
+ when "bitbucket"
242
+ bitbucket_client.fetch_file_contents(repo, commit, path)
243
+ else raise "Unsupported provider '#{provider}'."
244
+ end
245
+ end
246
+
247
+ # rubocop:disable Metrics/AbcSize
248
+ def fetch_file_content_from_github(path, repo, commit)
249
+ tmp = github_client_for_source.contents(repo, path: path, ref: commit)
250
+
251
+ if tmp.type == "symlink"
252
+ tmp = github_client_for_source.contents(
253
+ repo,
254
+ path: tmp.target,
255
+ ref: commit
256
+ )
257
+ end
258
+
259
+ Base64.decode64(tmp.content).force_encoding("UTF-8").encode
260
+ rescue Octokit::Forbidden => error
261
+ raise unless error.message.include?("too_large")
262
+
263
+ # Fall back to Git Data API to fetch the file
264
+ prefix_dir = directory.gsub(%r{(^/|/$)}, "")
265
+ dir = File.dirname(path).gsub(%r{^/?#{Regexp.escape(prefix_dir)}/?}, "")
266
+ basename = File.basename(path)
267
+ file_details = repo_contents(dir: dir).find { |f| f.name == basename }
268
+ raise unless file_details
269
+
270
+ tmp = github_client_for_source.blob(repo, file_details.sha)
271
+ return tmp.content if tmp.encoding == "utf-8"
272
+
273
+ Base64.decode64(tmp.content).force_encoding("UTF-8").encode
274
+ end
275
+ # rubocop:enable Metrics/AbcSize
276
+
277
+ def github_client_for_source
278
+ @github_client_for_source ||=
279
+ Dependabot::Clients::GithubWithRetries.for_source(
280
+ source: source,
281
+ credentials: credentials
282
+ )
283
+ end
284
+
285
+ def gitlab_client
286
+ @gitlab_client ||=
287
+ Dependabot::Clients::Gitlab.for_source(
288
+ source: source,
289
+ credentials: credentials
290
+ )
291
+ end
292
+
293
+ def bitbucket_client
294
+ # TODO: When self-hosted Bitbucket is supported this should use
295
+ # `Bitbucket.for_source`
296
+ @bitbucket_client ||=
297
+ Dependabot::Clients::Bitbucket.
298
+ for_bitbucket_dot_org(credentials: credentials)
299
+ end
300
+ end
301
+ end
302
+ end