rubygems-update 3.3.18 → 3.4.19

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 (615) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1429 -1064
  3. data/CONTRIBUTING.md +31 -8
  4. data/Manifest.txt +61 -36
  5. data/POLICIES.md +55 -20
  6. data/README.md +19 -6
  7. data/bundler/CHANGELOG.md +457 -1
  8. data/bundler/README.md +3 -6
  9. data/bundler/UPGRADING.md +11 -4
  10. data/bundler/bundler.gemspec +8 -10
  11. data/bundler/exe/bundle +5 -16
  12. data/bundler/lib/bundler/build_metadata.rb +2 -2
  13. data/bundler/lib/bundler/cli/add.rb +1 -1
  14. data/bundler/lib/bundler/cli/binstubs.rb +6 -2
  15. data/bundler/lib/bundler/cli/check.rb +1 -1
  16. data/bundler/lib/bundler/cli/common.rb +2 -0
  17. data/bundler/lib/bundler/cli/console.rb +2 -2
  18. data/bundler/lib/bundler/cli/doctor.rb +4 -6
  19. data/bundler/lib/bundler/cli/gem.rb +62 -40
  20. data/bundler/lib/bundler/cli/info.rb +1 -1
  21. data/bundler/lib/bundler/cli/init.rb +6 -2
  22. data/bundler/lib/bundler/cli/install.rb +8 -6
  23. data/bundler/lib/bundler/cli/lock.rb +8 -5
  24. data/bundler/lib/bundler/cli/open.rb +6 -4
  25. data/bundler/lib/bundler/cli/outdated.rb +14 -7
  26. data/bundler/lib/bundler/cli/platform.rb +7 -5
  27. data/bundler/lib/bundler/cli/viz.rb +1 -1
  28. data/bundler/lib/bundler/cli.rb +53 -7
  29. data/bundler/lib/bundler/compact_index_client/cache.rb +1 -1
  30. data/bundler/lib/bundler/compact_index_client/updater.rb +40 -39
  31. data/bundler/lib/bundler/constants.rb +1 -1
  32. data/bundler/lib/bundler/current_ruby.rb +16 -5
  33. data/bundler/lib/bundler/definition.rb +262 -133
  34. data/bundler/lib/bundler/dependency.rb +20 -86
  35. data/bundler/lib/bundler/digest.rb +1 -1
  36. data/bundler/lib/bundler/dsl.rb +6 -7
  37. data/bundler/lib/bundler/endpoint_specification.rb +2 -13
  38. data/bundler/lib/bundler/env.rb +2 -2
  39. data/bundler/lib/bundler/environment_preserver.rb +3 -2
  40. data/bundler/lib/bundler/errors.rb +1 -11
  41. data/bundler/lib/bundler/feature_flag.rb +0 -2
  42. data/bundler/lib/bundler/fetcher/compact_index.rb +11 -13
  43. data/bundler/lib/bundler/fetcher/dependency.rb +2 -6
  44. data/bundler/lib/bundler/fetcher/downloader.rb +4 -5
  45. data/bundler/lib/bundler/fetcher/index.rb +1 -2
  46. data/bundler/lib/bundler/fetcher.rb +21 -15
  47. data/bundler/lib/bundler/force_platform.rb +18 -0
  48. data/bundler/lib/bundler/friendly_errors.rb +1 -4
  49. data/bundler/lib/bundler/gem_helper.rb +3 -4
  50. data/bundler/lib/bundler/gem_helpers.rb +7 -2
  51. data/bundler/lib/bundler/gem_version_promoter.rb +53 -98
  52. data/bundler/lib/bundler/graph.rb +3 -3
  53. data/bundler/lib/bundler/index.rb +13 -47
  54. data/bundler/lib/bundler/injector.rb +5 -4
  55. data/bundler/lib/bundler/inline.rb +9 -11
  56. data/bundler/lib/bundler/installer/parallel_installer.rb +4 -34
  57. data/bundler/lib/bundler/installer/standalone.rb +13 -9
  58. data/bundler/lib/bundler/installer.rb +17 -29
  59. data/bundler/lib/bundler/lazy_specification.rb +54 -53
  60. data/bundler/lib/bundler/lockfile_generator.rb +3 -3
  61. data/bundler/lib/bundler/lockfile_parser.rb +17 -16
  62. data/bundler/lib/bundler/man/bundle-add.1 +6 -2
  63. data/bundler/lib/bundler/man/bundle-add.1.ronn +4 -1
  64. data/bundler/lib/bundler/man/bundle-binstubs.1 +1 -1
  65. data/bundler/lib/bundler/man/bundle-cache.1 +9 -3
  66. data/bundler/lib/bundler/man/bundle-cache.1.ronn +9 -2
  67. data/bundler/lib/bundler/man/bundle-check.1 +1 -1
  68. data/bundler/lib/bundler/man/bundle-clean.1 +2 -2
  69. data/bundler/lib/bundler/man/bundle-clean.1.ronn +1 -1
  70. data/bundler/lib/bundler/man/bundle-config.1 +26 -10
  71. data/bundler/lib/bundler/man/bundle-config.1.ronn +17 -10
  72. data/bundler/lib/bundler/man/bundle-console.1 +53 -0
  73. data/bundler/lib/bundler/man/bundle-console.1.ronn +44 -0
  74. data/bundler/lib/bundler/man/bundle-doctor.1 +1 -1
  75. data/bundler/lib/bundler/man/bundle-exec.1 +6 -6
  76. data/bundler/lib/bundler/man/bundle-exec.1.ronn +6 -6
  77. data/bundler/lib/bundler/man/bundle-gem.1 +27 -37
  78. data/bundler/lib/bundler/man/bundle-gem.1.ronn +5 -5
  79. data/bundler/lib/bundler/man/bundle-help.1 +13 -0
  80. data/bundler/lib/bundler/man/bundle-help.1.ronn +12 -0
  81. data/bundler/lib/bundler/man/bundle-info.1 +3 -3
  82. data/bundler/lib/bundler/man/bundle-info.1.ronn +3 -3
  83. data/bundler/lib/bundler/man/bundle-init.1 +5 -1
  84. data/bundler/lib/bundler/man/bundle-init.1.ronn +2 -0
  85. data/bundler/lib/bundler/man/bundle-inject.1 +5 -2
  86. data/bundler/lib/bundler/man/bundle-inject.1.ronn +3 -1
  87. data/bundler/lib/bundler/man/bundle-install.1 +5 -30
  88. data/bundler/lib/bundler/man/bundle-install.1.ronn +6 -29
  89. data/bundler/lib/bundler/man/bundle-list.1 +1 -1
  90. data/bundler/lib/bundler/man/bundle-lock.1 +1 -1
  91. data/bundler/lib/bundler/man/bundle-open.1 +22 -2
  92. data/bundler/lib/bundler/man/bundle-open.1.ronn +9 -1
  93. data/bundler/lib/bundler/man/bundle-outdated.1 +13 -9
  94. data/bundler/lib/bundler/man/bundle-outdated.1.ronn +12 -9
  95. data/bundler/lib/bundler/man/bundle-platform.1 +16 -6
  96. data/bundler/lib/bundler/man/bundle-platform.1.ronn +14 -7
  97. data/bundler/lib/bundler/man/bundle-plugin.1 +81 -0
  98. data/bundler/lib/bundler/man/bundle-plugin.1.ronn +59 -0
  99. data/bundler/lib/bundler/man/bundle-pristine.1 +1 -1
  100. data/bundler/lib/bundler/man/bundle-remove.1 +1 -1
  101. data/bundler/lib/bundler/man/bundle-show.1 +1 -1
  102. data/bundler/lib/bundler/man/bundle-update.1 +1 -1
  103. data/bundler/lib/bundler/man/bundle-version.1 +35 -0
  104. data/bundler/lib/bundler/man/bundle-version.1.ronn +24 -0
  105. data/bundler/lib/bundler/man/bundle-viz.1 +4 -1
  106. data/bundler/lib/bundler/man/bundle-viz.1.ronn +2 -0
  107. data/bundler/lib/bundler/man/bundle.1 +15 -10
  108. data/bundler/lib/bundler/man/bundle.1.ronn +12 -7
  109. data/bundler/lib/bundler/man/gemfile.5 +55 -55
  110. data/bundler/lib/bundler/man/gemfile.5.ronn +57 -53
  111. data/bundler/lib/bundler/man/index.txt +4 -0
  112. data/bundler/lib/bundler/match_metadata.rb +13 -0
  113. data/bundler/lib/bundler/match_remote_metadata.rb +29 -0
  114. data/bundler/lib/bundler/mirror.rb +5 -7
  115. data/bundler/lib/bundler/plugin/index.rb +5 -5
  116. data/bundler/lib/bundler/plugin/installer/rubygems.rb +0 -4
  117. data/bundler/lib/bundler/plugin/installer.rb +5 -2
  118. data/bundler/lib/bundler/plugin.rb +3 -1
  119. data/bundler/lib/bundler/remote_specification.rb +7 -12
  120. data/bundler/lib/bundler/resolver/base.rb +107 -0
  121. data/bundler/lib/bundler/resolver/candidate.rb +94 -0
  122. data/bundler/lib/bundler/resolver/incompatibility.rb +15 -0
  123. data/bundler/lib/bundler/resolver/package.rb +72 -0
  124. data/bundler/lib/bundler/resolver/root.rb +25 -0
  125. data/bundler/lib/bundler/resolver/spec_group.rb +42 -71
  126. data/bundler/lib/bundler/resolver.rb +335 -328
  127. data/bundler/lib/bundler/ruby_dsl.rb +7 -1
  128. data/bundler/lib/bundler/ruby_version.rb +8 -8
  129. data/bundler/lib/bundler/rubygems_ext.rb +100 -9
  130. data/bundler/lib/bundler/rubygems_gem_installer.rb +23 -14
  131. data/bundler/lib/bundler/rubygems_integration.rb +11 -15
  132. data/bundler/lib/bundler/runtime.rb +2 -6
  133. data/bundler/lib/bundler/safe_marshal.rb +31 -0
  134. data/bundler/lib/bundler/settings.rb +5 -11
  135. data/bundler/lib/bundler/setup.rb +4 -1
  136. data/bundler/lib/bundler/shared_helpers.rb +3 -3
  137. data/bundler/lib/bundler/source/git/git_proxy.rb +237 -74
  138. data/bundler/lib/bundler/source/git.rb +55 -30
  139. data/bundler/lib/bundler/source/metadata.rb +1 -2
  140. data/bundler/lib/bundler/source/path/installer.rb +1 -22
  141. data/bundler/lib/bundler/source/path.rb +6 -6
  142. data/bundler/lib/bundler/source/rubygems.rb +26 -81
  143. data/bundler/lib/bundler/source.rb +1 -1
  144. data/bundler/lib/bundler/source_list.rb +8 -2
  145. data/bundler/lib/bundler/spec_set.rb +60 -37
  146. data/bundler/lib/bundler/templates/Executable +1 -1
  147. data/bundler/lib/bundler/templates/Executable.bundler +5 -10
  148. data/bundler/lib/bundler/templates/Executable.standalone +2 -0
  149. data/bundler/lib/bundler/templates/newgem/Cargo.toml.tt +7 -0
  150. data/bundler/lib/bundler/templates/newgem/Gemfile.tt +3 -0
  151. data/bundler/lib/bundler/templates/newgem/README.md.tt +6 -4
  152. data/bundler/lib/bundler/templates/newgem/Rakefile.tt +12 -1
  153. data/bundler/lib/bundler/templates/newgem/bin/console.tt +0 -4
  154. data/bundler/lib/bundler/templates/newgem/circleci/config.yml.tt +12 -0
  155. data/bundler/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt +15 -0
  156. data/bundler/lib/bundler/templates/newgem/ext/newgem/extconf-c.rb.tt +10 -0
  157. data/bundler/lib/bundler/templates/newgem/ext/newgem/extconf-rust.rb.tt +6 -0
  158. data/bundler/lib/bundler/templates/newgem/ext/newgem/newgem.c.tt +1 -1
  159. data/bundler/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt +12 -0
  160. data/bundler/lib/bundler/templates/newgem/github/workflows/main.yml.tt +10 -0
  161. data/bundler/lib/bundler/templates/newgem/gitignore.tt +3 -0
  162. data/bundler/lib/bundler/templates/newgem/gitlab-ci.yml.tt +13 -4
  163. data/bundler/lib/bundler/templates/newgem/newgem.gemspec.tt +9 -2
  164. data/bundler/lib/bundler/ui/rg_proxy.rb +1 -1
  165. data/bundler/lib/bundler/ui/shell.rb +35 -12
  166. data/bundler/lib/bundler/ui/silent.rb +21 -5
  167. data/bundler/lib/bundler/uri_normalizer.rb +23 -0
  168. data/bundler/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb +3 -3
  169. data/bundler/lib/bundler/vendor/connection_pool/lib/connection_pool/wrapper.rb +0 -1
  170. data/bundler/lib/bundler/vendor/connection_pool/lib/connection_pool.rb +3 -1
  171. data/bundler/lib/bundler/vendor/fileutils/lib/fileutils.rb +1351 -409
  172. data/bundler/lib/bundler/vendor/net-http-persistent/README.rdoc +1 -1
  173. data/bundler/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +1 -1
  174. data/bundler/lib/bundler/vendor/pub_grub/LICENSE.txt +21 -0
  175. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/assignment.rb +20 -0
  176. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/basic_package_source.rb +189 -0
  177. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/failure_writer.rb +182 -0
  178. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/incompatibility.rb +150 -0
  179. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/package.rb +43 -0
  180. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/partial_solution.rb +121 -0
  181. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/rubygems.rb +45 -0
  182. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/solve_failure.rb +19 -0
  183. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/static_package_source.rb +60 -0
  184. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/term.rb +105 -0
  185. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/version.rb +3 -0
  186. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/version_constraint.rb +129 -0
  187. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/version_range.rb +411 -0
  188. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/version_solver.rb +248 -0
  189. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/version_union.rb +178 -0
  190. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub.rb +31 -0
  191. data/bundler/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +1 -1
  192. data/bundler/lib/bundler/vendor/uri/lib/uri/common.rb +64 -16
  193. data/bundler/lib/bundler/vendor/uri/lib/uri/file.rb +7 -1
  194. data/bundler/lib/bundler/vendor/uri/lib/uri/ftp.rb +2 -1
  195. data/bundler/lib/bundler/vendor/uri/lib/uri/generic.rb +27 -7
  196. data/bundler/lib/bundler/vendor/uri/lib/uri/http.rb +40 -2
  197. data/bundler/lib/bundler/vendor/uri/lib/uri/https.rb +2 -1
  198. data/bundler/lib/bundler/vendor/uri/lib/uri/ldap.rb +1 -1
  199. data/bundler/lib/bundler/vendor/uri/lib/uri/ldaps.rb +2 -1
  200. data/bundler/lib/bundler/vendor/uri/lib/uri/mailto.rb +2 -2
  201. data/bundler/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb +15 -9
  202. data/bundler/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb +11 -6
  203. data/bundler/lib/bundler/vendor/uri/lib/uri/version.rb +1 -1
  204. data/bundler/lib/bundler/vendor/uri/lib/uri/ws.rb +1 -2
  205. data/bundler/lib/bundler/vendor/uri/lib/uri/wss.rb +2 -1
  206. data/bundler/lib/bundler/vendor/uri/lib/uri.rb +3 -2
  207. data/bundler/lib/bundler/vendored_persistent.rb +1 -33
  208. data/bundler/lib/bundler/{vendored_tmpdir.rb → vendored_pub_grub.rb} +1 -1
  209. data/bundler/lib/bundler/version.rb +5 -1
  210. data/bundler/lib/bundler/worker.rb +5 -7
  211. data/bundler/lib/bundler.rb +25 -77
  212. data/{bin → exe}/gem +4 -5
  213. data/{bin → exe}/update_rubygems +12 -10
  214. data/lib/rubygems/available_set.rb +4 -3
  215. data/lib/rubygems/basic_specification.rb +5 -4
  216. data/lib/rubygems/bundler_version_finder.rb +2 -2
  217. data/lib/rubygems/command.rb +41 -32
  218. data/lib/rubygems/command_manager.rb +30 -15
  219. data/lib/rubygems/commands/build_command.rb +12 -8
  220. data/lib/rubygems/commands/cert_command.rb +34 -33
  221. data/lib/rubygems/commands/check_command.rb +21 -20
  222. data/lib/rubygems/commands/cleanup_command.rb +18 -17
  223. data/lib/rubygems/commands/contents_command.rb +14 -13
  224. data/lib/rubygems/commands/dependency_command.rb +17 -16
  225. data/lib/rubygems/commands/environment_command.rb +6 -5
  226. data/lib/rubygems/commands/exec_command.rb +249 -0
  227. data/lib/rubygems/commands/fetch_command.rb +10 -9
  228. data/lib/rubygems/commands/generate_index_command.rb +18 -17
  229. data/lib/rubygems/commands/help_command.rb +7 -6
  230. data/lib/rubygems/commands/info_command.rb +3 -3
  231. data/lib/rubygems/commands/install_command.rb +28 -23
  232. data/lib/rubygems/commands/list_command.rb +4 -3
  233. data/lib/rubygems/commands/lock_command.rb +5 -4
  234. data/lib/rubygems/commands/mirror_command.rb +4 -3
  235. data/lib/rubygems/commands/open_command.rb +10 -9
  236. data/lib/rubygems/commands/outdated_command.rb +6 -5
  237. data/lib/rubygems/commands/owner_command.rb +17 -14
  238. data/lib/rubygems/commands/pristine_command.rb +46 -36
  239. data/lib/rubygems/commands/push_command.rb +9 -8
  240. data/lib/rubygems/commands/query_command.rb +9 -8
  241. data/lib/rubygems/commands/rdoc_command.rb +21 -19
  242. data/lib/rubygems/commands/search_command.rb +4 -3
  243. data/lib/rubygems/commands/server_command.rb +4 -3
  244. data/lib/rubygems/commands/setup_command.rb +97 -106
  245. data/lib/rubygems/commands/signin_command.rb +10 -9
  246. data/lib/rubygems/commands/signout_command.rb +8 -7
  247. data/lib/rubygems/commands/sources_command.rb +22 -21
  248. data/lib/rubygems/commands/specification_command.rb +14 -13
  249. data/lib/rubygems/commands/stale_command.rb +3 -2
  250. data/lib/rubygems/commands/uninstall_command.rb +44 -40
  251. data/lib/rubygems/commands/unpack_command.rb +14 -13
  252. data/lib/rubygems/commands/update_command.rb +42 -63
  253. data/lib/rubygems/commands/which_command.rb +8 -7
  254. data/lib/rubygems/commands/yank_command.rb +12 -11
  255. data/lib/rubygems/config_file.rb +55 -21
  256. data/lib/rubygems/core_ext/kernel_gem.rb +1 -6
  257. data/lib/rubygems/core_ext/kernel_require.rb +109 -115
  258. data/lib/rubygems/core_ext/kernel_warn.rb +33 -37
  259. data/lib/rubygems/core_ext/tcpsocket_init.rb +3 -1
  260. data/lib/rubygems/defaults.rb +33 -18
  261. data/lib/rubygems/dependency.rb +15 -11
  262. data/lib/rubygems/dependency_installer.rb +38 -37
  263. data/lib/rubygems/dependency_list.rb +7 -6
  264. data/lib/rubygems/deprecate.rb +3 -2
  265. data/lib/rubygems/doctor.rb +19 -18
  266. data/lib/rubygems/errors.rb +3 -2
  267. data/lib/rubygems/exceptions.rb +16 -8
  268. data/lib/rubygems/ext/build_error.rb +2 -1
  269. data/lib/rubygems/ext/builder.rb +37 -21
  270. data/lib/rubygems/ext/cargo_builder/link_flag_converter.rb +9 -5
  271. data/lib/rubygems/ext/cargo_builder.rb +150 -111
  272. data/lib/rubygems/ext/cmake_builder.rb +2 -2
  273. data/lib/rubygems/ext/configure_builder.rb +2 -1
  274. data/lib/rubygems/ext/ext_conf_builder.rb +11 -9
  275. data/lib/rubygems/ext/rake_builder.rb +7 -5
  276. data/lib/rubygems/ext.rb +8 -7
  277. data/lib/rubygems/gem_runner.rb +6 -5
  278. data/lib/rubygems/gemcutter_utilities/webauthn_listener/response.rb +163 -0
  279. data/lib/rubygems/gemcutter_utilities/webauthn_listener.rb +105 -0
  280. data/lib/rubygems/gemcutter_utilities/webauthn_poller.rb +78 -0
  281. data/lib/rubygems/gemcutter_utilities.rb +90 -34
  282. data/lib/rubygems/indexer.rb +29 -28
  283. data/lib/rubygems/install_default_message.rb +3 -2
  284. data/lib/rubygems/install_message.rb +3 -2
  285. data/lib/rubygems/install_update_options.rb +56 -55
  286. data/lib/rubygems/installer.rb +54 -46
  287. data/lib/rubygems/installer_uninstaller_utils.rb +2 -2
  288. data/lib/rubygems/local_remote_options.rb +19 -20
  289. data/lib/rubygems/mock_gem_ui.rb +3 -2
  290. data/lib/rubygems/name_tuple.rb +5 -4
  291. data/lib/rubygems/optparse/lib/optparse.rb +20 -15
  292. data/lib/rubygems/optparse.rb +1 -1
  293. data/lib/rubygems/package/digest_io.rb +1 -0
  294. data/lib/rubygems/package/file_source.rb +3 -2
  295. data/lib/rubygems/package/io_source.rb +1 -0
  296. data/lib/rubygems/package/old.rb +9 -8
  297. data/lib/rubygems/package/source.rb +1 -0
  298. data/lib/rubygems/package/tar_header.rb +63 -62
  299. data/lib/rubygems/package/tar_reader/entry.rb +91 -9
  300. data/lib/rubygems/package/tar_reader.rb +2 -29
  301. data/lib/rubygems/package/tar_writer.rb +8 -7
  302. data/lib/rubygems/package.rb +64 -48
  303. data/lib/rubygems/package_task.rb +5 -4
  304. data/lib/rubygems/path_support.rb +1 -0
  305. data/lib/rubygems/platform.rb +79 -53
  306. data/lib/rubygems/psych_tree.rb +2 -1
  307. data/lib/rubygems/query_utils.rb +35 -35
  308. data/lib/rubygems/rdoc.rb +3 -2
  309. data/lib/rubygems/remote_fetcher.rb +23 -22
  310. data/lib/rubygems/request/connection_pools.rb +4 -4
  311. data/lib/rubygems/request/http_pool.rb +2 -1
  312. data/lib/rubygems/request/https_pool.rb +1 -0
  313. data/lib/rubygems/request.rb +23 -22
  314. data/lib/rubygems/request_set/gem_dependency_api.rb +123 -123
  315. data/lib/rubygems/request_set/lockfile/parser.rb +28 -27
  316. data/lib/rubygems/request_set/lockfile/tokenizer.rb +5 -3
  317. data/lib/rubygems/request_set/lockfile.rb +6 -5
  318. data/lib/rubygems/request_set.rb +20 -19
  319. data/lib/rubygems/requirement.rb +15 -14
  320. data/lib/rubygems/resolver/activation_request.rb +4 -3
  321. data/lib/rubygems/resolver/api_set.rb +5 -4
  322. data/lib/rubygems/resolver/api_specification.rb +7 -6
  323. data/lib/rubygems/resolver/best_set.rb +6 -5
  324. data/lib/rubygems/resolver/composed_set.rb +1 -0
  325. data/lib/rubygems/resolver/conflict.rb +11 -10
  326. data/lib/rubygems/resolver/current_set.rb +1 -0
  327. data/lib/rubygems/resolver/dependency_request.rb +3 -2
  328. data/lib/rubygems/resolver/git_set.rb +3 -2
  329. data/lib/rubygems/resolver/git_specification.rb +7 -6
  330. data/lib/rubygems/resolver/index_set.rb +4 -3
  331. data/lib/rubygems/resolver/index_specification.rb +7 -5
  332. data/lib/rubygems/resolver/installed_specification.rb +5 -4
  333. data/lib/rubygems/resolver/installer_set.rb +15 -17
  334. data/lib/rubygems/resolver/local_specification.rb +3 -2
  335. data/lib/rubygems/resolver/lock_set.rb +5 -4
  336. data/lib/rubygems/resolver/lock_specification.rb +5 -4
  337. data/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb +1 -1
  338. data/lib/rubygems/resolver/molinillo/lib/molinillo/errors.rb +32 -26
  339. data/lib/rubygems/resolver/molinillo/lib/molinillo/gem_metadata.rb +1 -1
  340. data/lib/rubygems/resolver/molinillo.rb +2 -1
  341. data/lib/rubygems/resolver/requirement_list.rb +1 -0
  342. data/lib/rubygems/resolver/set.rb +1 -0
  343. data/lib/rubygems/resolver/source_set.rb +2 -0
  344. data/lib/rubygems/resolver/spec_specification.rb +1 -0
  345. data/lib/rubygems/resolver/specification.rb +2 -1
  346. data/lib/rubygems/resolver/stats.rb +2 -1
  347. data/lib/rubygems/resolver/vendor_set.rb +2 -1
  348. data/lib/rubygems/resolver/vendor_specification.rb +4 -3
  349. data/lib/rubygems/resolver.rb +41 -40
  350. data/lib/rubygems/s3_uri_signer.rb +10 -8
  351. data/lib/rubygems/safe_yaml.rb +4 -2
  352. data/lib/rubygems/security/policies.rb +48 -47
  353. data/lib/rubygems/security/policy.rb +19 -18
  354. data/lib/rubygems/security/signer.rb +6 -5
  355. data/lib/rubygems/security/trust_dir.rb +5 -4
  356. data/lib/rubygems/security.rb +30 -42
  357. data/lib/rubygems/security_option.rb +6 -5
  358. data/lib/rubygems/shellwords.rb +3 -0
  359. data/lib/rubygems/source/git.rb +22 -22
  360. data/lib/rubygems/source/installed.rb +2 -1
  361. data/lib/rubygems/source/local.rb +3 -2
  362. data/lib/rubygems/source/lock.rb +1 -0
  363. data/lib/rubygems/source/specific_file.rb +2 -1
  364. data/lib/rubygems/source/vendor.rb +1 -0
  365. data/lib/rubygems/source.rb +16 -16
  366. data/lib/rubygems/spec_fetcher.rb +10 -9
  367. data/lib/rubygems/specification.rb +121 -114
  368. data/lib/rubygems/specification_policy.rb +36 -15
  369. data/lib/rubygems/stub_specification.rb +11 -9
  370. data/lib/rubygems/text.rb +2 -2
  371. data/lib/rubygems/tsort/lib/tsort.rb +308 -310
  372. data/lib/rubygems/tsort.rb +1 -1
  373. data/lib/rubygems/uninstaller.rb +19 -18
  374. data/lib/rubygems/update_suggestion.rb +69 -0
  375. data/lib/rubygems/uri.rb +4 -4
  376. data/lib/rubygems/uri_formatter.rb +1 -1
  377. data/lib/rubygems/user_interaction.rb +37 -21
  378. data/lib/rubygems/util/licenses.rb +4 -3
  379. data/lib/rubygems/util/list.rb +1 -0
  380. data/lib/rubygems/util.rb +12 -15
  381. data/lib/rubygems/validator.rb +7 -6
  382. data/lib/rubygems/version.rb +17 -11
  383. data/lib/rubygems/version_option.rb +4 -3
  384. data/lib/rubygems.rb +89 -68
  385. data/rubygems-update.gemspec +10 -8
  386. data/setup.rb +10 -9
  387. data/test/rubygems/alternate_cert.pem +14 -14
  388. data/test/rubygems/alternate_cert_32.pem +15 -15
  389. data/test/rubygems/alternate_key.pem +25 -25
  390. data/test/rubygems/bad_rake.rb +1 -0
  391. data/test/rubygems/bundler_test_gem.rb +421 -0
  392. data/test/rubygems/child_cert.pem +15 -16
  393. data/test/rubygems/child_cert_32.pem +15 -16
  394. data/test/rubygems/child_key.pem +25 -25
  395. data/test/rubygems/encrypted_private_key.pem +26 -26
  396. data/test/rubygems/expired_cert.pem +15 -15
  397. data/test/rubygems/fake_certlib/openssl.rb +1 -0
  398. data/test/rubygems/future_cert.pem +15 -15
  399. data/test/rubygems/future_cert_32.pem +15 -15
  400. data/test/rubygems/good_rake.rb +1 -0
  401. data/test/rubygems/grandchild_cert.pem +15 -16
  402. data/test/rubygems/grandchild_cert_32.pem +15 -16
  403. data/test/rubygems/grandchild_key.pem +25 -25
  404. data/test/rubygems/helper.rb +172 -151
  405. data/test/rubygems/installer_test_case.rb +14 -13
  406. data/test/rubygems/invalid_issuer_cert.pem +16 -16
  407. data/test/rubygems/invalid_issuer_cert_32.pem +16 -16
  408. data/test/rubygems/invalid_key.pem +25 -25
  409. data/test/rubygems/invalid_signer_cert.pem +15 -15
  410. data/test/rubygems/invalid_signer_cert_32.pem +15 -15
  411. data/test/rubygems/invalidchild_cert.pem +15 -16
  412. data/test/rubygems/invalidchild_cert_32.pem +15 -16
  413. data/test/rubygems/invalidchild_key.pem +25 -25
  414. data/test/rubygems/multifactor_auth_utilities.rb +111 -0
  415. data/test/rubygems/package/tar_test_case.rb +53 -17
  416. data/test/rubygems/packages/Bluebie-legs-0.6.2.gem +0 -0
  417. data/test/rubygems/plugin/exception/rubygems_plugin.rb +2 -1
  418. data/test/rubygems/plugin/load/rubygems_plugin.rb +1 -0
  419. data/test/rubygems/plugin/standarderror/rubygems_plugin.rb +2 -1
  420. data/test/rubygems/private_key.pem +25 -25
  421. data/test/rubygems/public_cert.pem +16 -16
  422. data/test/rubygems/public_cert_32.pem +15 -15
  423. data/test/rubygems/public_key.pem +7 -7
  424. data/test/rubygems/rubygems/commands/crash_command.rb +1 -0
  425. data/test/rubygems/rubygems_plugin.rb +3 -2
  426. data/test/rubygems/simple_gem.rb +2 -1
  427. data/test/rubygems/specifications/bar-0.0.2.gemspec +2 -0
  428. data/test/rubygems/specifications/rubyforge-0.0.1.gemspec +6 -4
  429. data/test/rubygems/test_bundled_ca.rb +13 -12
  430. data/test/rubygems/test_config.rb +5 -4
  431. data/test/rubygems/test_deprecate.rb +5 -4
  432. data/test/rubygems/test_exit.rb +9 -3
  433. data/test/rubygems/test_gem.rb +339 -677
  434. data/test/rubygems/test_gem_available_set.rb +22 -21
  435. data/test/rubygems/test_gem_bundler_version_finder.rb +6 -4
  436. data/test/rubygems/test_gem_command.rb +45 -44
  437. data/test/rubygems/test_gem_command_manager.rb +96 -30
  438. data/test/rubygems/test_gem_commands_build_command.rb +74 -63
  439. data/test/rubygems/test_gem_commands_cert_command.rb +98 -99
  440. data/test/rubygems/test_gem_commands_check_command.rb +5 -4
  441. data/test/rubygems/test_gem_commands_cleanup_command.rb +41 -40
  442. data/test/rubygems/test_gem_commands_contents_command.rb +28 -27
  443. data/test/rubygems/test_gem_commands_dependency_command.rb +37 -36
  444. data/test/rubygems/test_gem_commands_environment_command.rb +17 -16
  445. data/test/rubygems/test_gem_commands_exec_command.rb +853 -0
  446. data/test/rubygems/test_gem_commands_fetch_command.rb +38 -37
  447. data/test/rubygems/test_gem_commands_generate_index_command.rb +8 -7
  448. data/test/rubygems/test_gem_commands_help_command.rb +14 -13
  449. data/test/rubygems/test_gem_commands_info_command.rb +29 -2
  450. data/test/rubygems/test_gem_commands_install_command.rb +152 -132
  451. data/test/rubygems/test_gem_commands_list_command.rb +5 -4
  452. data/test/rubygems/test_gem_commands_lock_command.rb +11 -10
  453. data/test/rubygems/test_gem_commands_mirror.rb +3 -2
  454. data/test/rubygems/test_gem_commands_open_command.rb +5 -4
  455. data/test/rubygems/test_gem_commands_outdated_command.rb +10 -9
  456. data/test/rubygems/test_gem_commands_owner_command.rb +227 -50
  457. data/test/rubygems/test_gem_commands_pristine_command.rb +142 -93
  458. data/test/rubygems/test_gem_commands_push_command.rb +189 -64
  459. data/test/rubygems/test_gem_commands_query_command.rb +74 -73
  460. data/test/rubygems/test_gem_commands_search_command.rb +3 -2
  461. data/test/rubygems/test_gem_commands_server_command.rb +3 -2
  462. data/test/rubygems/test_gem_commands_setup_command.rb +123 -96
  463. data/test/rubygems/test_gem_commands_signin_command.rb +71 -31
  464. data/test/rubygems/test_gem_commands_signout_command.rb +3 -3
  465. data/test/rubygems/test_gem_commands_sources_command.rb +29 -29
  466. data/test/rubygems/test_gem_commands_specification_command.rb +33 -32
  467. data/test/rubygems/test_gem_commands_stale_command.rb +5 -4
  468. data/test/rubygems/test_gem_commands_uninstall_command.rb +99 -81
  469. data/test/rubygems/test_gem_commands_unpack_command.rb +32 -31
  470. data/test/rubygems/test_gem_commands_update_command.rb +96 -95
  471. data/test/rubygems/test_gem_commands_which_command.rb +7 -6
  472. data/test/rubygems/test_gem_commands_yank_command.rb +162 -43
  473. data/test/rubygems/test_gem_config_file.rb +94 -81
  474. data/test/rubygems/test_gem_dependency.rb +76 -73
  475. data/test/rubygems/test_gem_dependency_installer.rb +200 -165
  476. data/test/rubygems/test_gem_dependency_list.rb +48 -47
  477. data/test/rubygems/test_gem_dependency_resolution_error.rb +5 -4
  478. data/test/rubygems/test_gem_doctor.rb +27 -26
  479. data/test/rubygems/test_gem_ext_builder.rb +60 -61
  480. data/test/rubygems/test_gem_ext_cargo_builder/custom_name/custom_name.gemspec +4 -4
  481. data/test/rubygems/test_gem_ext_cargo_builder/custom_name/{Cargo.lock → ext/custom_name_lib/Cargo.lock} +23 -33
  482. data/test/rubygems/test_gem_ext_cargo_builder/custom_name/{Cargo.toml → ext/custom_name_lib/Cargo.toml} +1 -1
  483. data/test/rubygems/test_gem_ext_cargo_builder/custom_name/{src → ext/custom_name_lib/src}/lib.rs +1 -1
  484. data/test/rubygems/test_gem_ext_cargo_builder/custom_name/lib/custom_name.rb +3 -0
  485. data/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock +37 -33
  486. data/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml +1 -1
  487. data/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/rust_ruby_example.gemspec +2 -0
  488. data/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/src/lib.rs +12 -0
  489. data/test/rubygems/test_gem_ext_cargo_builder.rb +48 -59
  490. data/test/rubygems/test_gem_ext_cargo_builder_link_flag_converter.rb +20 -19
  491. data/test/rubygems/test_gem_ext_cargo_builder_unit.rb +21 -36
  492. data/test/rubygems/test_gem_ext_cmake_builder.rb +16 -15
  493. data/test/rubygems/test_gem_ext_configure_builder.rb +14 -13
  494. data/test/rubygems/test_gem_ext_ext_conf_builder.rb +51 -52
  495. data/test/rubygems/test_gem_ext_rake_builder.rb +16 -15
  496. data/test/rubygems/test_gem_gem_runner.rb +15 -9
  497. data/test/rubygems/test_gem_gemcutter_utilities.rb +170 -84
  498. data/test/rubygems/test_gem_impossible_dependencies_error.rb +5 -4
  499. data/test/rubygems/test_gem_indexer.rb +87 -67
  500. data/test/rubygems/test_gem_install_update_options.rb +17 -16
  501. data/test/rubygems/test_gem_installer.rb +422 -304
  502. data/test/rubygems/test_gem_local_remote_options.rb +11 -10
  503. data/test/rubygems/test_gem_name_tuple.rb +5 -4
  504. data/test/rubygems/test_gem_package.rb +243 -231
  505. data/test/rubygems/test_gem_package_old.rb +14 -13
  506. data/test/rubygems/test_gem_package_tar_header.rb +48 -47
  507. data/test/rubygems/test_gem_package_tar_reader.rb +56 -8
  508. data/test/rubygems/test_gem_package_tar_reader_entry.rb +162 -16
  509. data/test/rubygems/test_gem_package_tar_writer.rb +77 -76
  510. data/test/rubygems/test_gem_package_task.rb +19 -18
  511. data/test/rubygems/test_gem_path_support.rb +15 -14
  512. data/test/rubygems/test_gem_platform.rb +333 -227
  513. data/test/rubygems/test_gem_rdoc.rb +15 -14
  514. data/test/rubygems/test_gem_remote_fetcher.rb +155 -154
  515. data/test/rubygems/test_gem_request.rb +64 -58
  516. data/test/rubygems/test_gem_request_connection_pools.rb +30 -29
  517. data/test/rubygems/test_gem_request_set.rb +101 -100
  518. data/test/rubygems/test_gem_request_set_gem_dependency_api.rb +210 -211
  519. data/test/rubygems/test_gem_request_set_lockfile.rb +87 -86
  520. data/test/rubygems/test_gem_request_set_lockfile_parser.rb +58 -57
  521. data/test/rubygems/test_gem_request_set_lockfile_tokenizer.rb +63 -62
  522. data/test/rubygems/test_gem_requirement.rb +48 -41
  523. data/test/rubygems/test_gem_resolver.rb +167 -99
  524. data/test/rubygems/test_gem_resolver_activation_request.rb +7 -6
  525. data/test/rubygems/test_gem_resolver_api_set.rb +34 -33
  526. data/test/rubygems/test_gem_resolver_api_specification.rb +48 -47
  527. data/test/rubygems/test_gem_resolver_best_set.rb +23 -22
  528. data/test/rubygems/test_gem_resolver_composed_set.rb +2 -1
  529. data/test/rubygems/test_gem_resolver_conflict.rb +13 -12
  530. data/test/rubygems/test_gem_resolver_dependency_request.rb +16 -15
  531. data/test/rubygems/test_gem_resolver_git_set.rb +22 -21
  532. data/test/rubygems/test_gem_resolver_git_specification.rb +22 -21
  533. data/test/rubygems/test_gem_resolver_index_set.rb +13 -12
  534. data/test/rubygems/test_gem_resolver_index_specification.rb +17 -16
  535. data/test/rubygems/test_gem_resolver_installed_specification.rb +6 -5
  536. data/test/rubygems/test_gem_resolver_installer_set.rb +79 -34
  537. data/test/rubygems/test_gem_resolver_local_specification.rb +8 -7
  538. data/test/rubygems/test_gem_resolver_lock_set.rb +13 -12
  539. data/test/rubygems/test_gem_resolver_lock_specification.rb +18 -17
  540. data/test/rubygems/test_gem_resolver_requirement_list.rb +2 -1
  541. data/test/rubygems/test_gem_resolver_specification.rb +9 -8
  542. data/test/rubygems/test_gem_resolver_vendor_set.rb +7 -6
  543. data/test/rubygems/test_gem_resolver_vendor_specification.rb +11 -10
  544. data/test/rubygems/test_gem_security.rb +69 -68
  545. data/test/rubygems/test_gem_security_policy.rb +72 -72
  546. data/test/rubygems/test_gem_security_signer.rb +35 -34
  547. data/test/rubygems/test_gem_security_trust_dir.rb +7 -6
  548. data/test/rubygems/test_gem_silent_ui.rb +39 -32
  549. data/test/rubygems/test_gem_source.rb +45 -44
  550. data/test/rubygems/test_gem_source_fetch_problem.rb +10 -9
  551. data/test/rubygems/test_gem_source_git.rb +69 -62
  552. data/test/rubygems/test_gem_source_installed.rb +17 -16
  553. data/test/rubygems/test_gem_source_list.rb +6 -5
  554. data/test/rubygems/test_gem_source_local.rb +15 -14
  555. data/test/rubygems/test_gem_source_lock.rb +32 -31
  556. data/test/rubygems/test_gem_source_specific_file.rb +18 -17
  557. data/test/rubygems/test_gem_source_subpath_problem.rb +8 -7
  558. data/test/rubygems/test_gem_source_vendor.rb +14 -13
  559. data/test/rubygems/test_gem_spec_fetcher.rb +73 -72
  560. data/test/rubygems/test_gem_specification.rb +533 -469
  561. data/test/rubygems/test_gem_stream_ui.rb +53 -22
  562. data/test/rubygems/test_gem_stub_specification.rb +33 -32
  563. data/test/rubygems/test_gem_text.rb +2 -1
  564. data/test/rubygems/test_gem_uninstaller.rb +118 -117
  565. data/test/rubygems/test_gem_unsatisfiable_dependency_error.rb +4 -3
  566. data/test/rubygems/test_gem_update_suggestion.rb +209 -0
  567. data/test/rubygems/test_gem_uri.rb +6 -4
  568. data/test/rubygems/test_gem_uri_formatter.rb +15 -14
  569. data/test/rubygems/test_gem_util.rb +24 -23
  570. data/test/rubygems/test_gem_validator.rb +8 -8
  571. data/test/rubygems/test_gem_version.rb +24 -16
  572. data/test/rubygems/test_gem_version_option.rb +16 -15
  573. data/test/rubygems/test_kernel.rb +43 -48
  574. data/test/rubygems/test_project_sanity.rb +32 -3
  575. data/test/rubygems/test_remote_fetch_error.rb +8 -7
  576. data/test/rubygems/test_require.rb +118 -103
  577. data/test/rubygems/test_rubygems.rb +10 -8
  578. data/test/rubygems/test_webauthn_listener.rb +143 -0
  579. data/test/rubygems/test_webauthn_listener_response.rb +93 -0
  580. data/test/rubygems/test_webauthn_poller.rb +124 -0
  581. data/test/rubygems/utilities.rb +98 -34
  582. data/test/rubygems/wrong_key_cert.pem +15 -15
  583. data/test/rubygems/wrong_key_cert_32.pem +15 -15
  584. data/test/test_changelog_generator.rb +1 -1
  585. metadata +99 -46
  586. data/bundler/lib/bundler/dep_proxy.rb +0 -55
  587. data/bundler/lib/bundler/templates/gems.rb +0 -5
  588. data/bundler/lib/bundler/templates/newgem/ext/newgem/extconf.rb.tt +0 -5
  589. data/bundler/lib/bundler/templates/newgem/travis.yml.tt +0 -6
  590. data/bundler/lib/bundler/vendor/molinillo/LICENSE +0 -9
  591. data/bundler/lib/bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb +0 -57
  592. data/bundler/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb +0 -88
  593. data/bundler/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb +0 -36
  594. data/bundler/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb +0 -66
  595. data/bundler/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb +0 -62
  596. data/bundler/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb +0 -63
  597. data/bundler/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb +0 -61
  598. data/bundler/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb +0 -126
  599. data/bundler/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb +0 -46
  600. data/bundler/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb +0 -36
  601. data/bundler/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb +0 -164
  602. data/bundler/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +0 -255
  603. data/bundler/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb +0 -149
  604. data/bundler/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb +0 -6
  605. data/bundler/lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb +0 -112
  606. data/bundler/lib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rb +0 -67
  607. data/bundler/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb +0 -839
  608. data/bundler/lib/bundler/vendor/molinillo/lib/molinillo/resolver.rb +0 -46
  609. data/bundler/lib/bundler/vendor/molinillo/lib/molinillo/state.rb +0 -58
  610. data/bundler/lib/bundler/vendor/molinillo/lib/molinillo.rb +0 -11
  611. data/bundler/lib/bundler/vendor/tmpdir/lib/tmpdir.rb +0 -154
  612. data/bundler/lib/bundler/vendored_molinillo.rb +0 -4
  613. data/bundler/lib/bundler/version_ranges.rb +0 -122
  614. data/test/rubygems/test_gem_ext_cargo_builder/custom_name/build.rb +0 -21
  615. data/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/build.rb +0 -21
data/lib/rubygems/ext.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  #--
3
4
  # Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
4
5
  # All rights reserved.
@@ -10,10 +11,10 @@
10
11
 
11
12
  module Gem::Ext; end
12
13
 
13
- require_relative 'ext/build_error'
14
- require_relative 'ext/builder'
15
- require_relative 'ext/configure_builder'
16
- require_relative 'ext/ext_conf_builder'
17
- require_relative 'ext/rake_builder'
18
- require_relative 'ext/cmake_builder'
19
- require_relative 'ext/cargo_builder'
14
+ require_relative "ext/build_error"
15
+ require_relative "ext/builder"
16
+ require_relative "ext/configure_builder"
17
+ require_relative "ext/ext_conf_builder"
18
+ require_relative "ext/rake_builder"
19
+ require_relative "ext/cmake_builder"
20
+ require_relative "ext/cargo_builder"
@@ -1,13 +1,14 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  #--
3
4
  # Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
4
5
  # All rights reserved.
5
6
  # See LICENSE.txt for permissions.
6
7
  #++
7
8
 
8
- require_relative '../rubygems'
9
- require_relative 'command_manager'
10
- require_relative 'deprecate'
9
+ require_relative "../rubygems"
10
+ require_relative "command_manager"
11
+ require_relative "deprecate"
11
12
 
12
13
  ##
13
14
  # Run an instance of the gem program.
@@ -41,7 +42,7 @@ class Gem::GemRunner
41
42
  config_args = Gem.configuration[command_name]
42
43
  config_args = case config_args
43
44
  when String
44
- config_args.split ' '
45
+ config_args.split " "
45
46
  else
46
47
  Array(config_args)
47
48
  end
@@ -56,7 +57,7 @@ class Gem::GemRunner
56
57
  # other arguments in the list.
57
58
 
58
59
  def extract_build_args(args) # :nodoc:
59
- return [] unless offset = args.index('--')
60
+ return [] unless offset = args.index("--")
60
61
 
61
62
  build_args = args.slice!(offset...args.length)
62
63
 
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # The WebauthnListener Response class is used by the WebauthnListener to create
5
+ # responses to be sent to the Gem host. It creates a Net::HTTPResponse instance
6
+ # when initialized and can be converted to the appropriate format to be sent by a socket using `to_s`.
7
+ # Net::HTTPResponse instances cannot be directly sent over a socket.
8
+ #
9
+ # Types of response classes:
10
+ # - OkResponse
11
+ # - NoContentResponse
12
+ # - BadRequestResponse
13
+ # - NotFoundResponse
14
+ # - MethodNotAllowedResponse
15
+ #
16
+ # Example usage:
17
+ #
18
+ # server = TCPServer.new(0)
19
+ # socket = server.accept
20
+ #
21
+ # response = OkResponse.for("https://rubygems.example")
22
+ # socket.print response.to_s
23
+ # socket.close
24
+ #
25
+
26
+ module Gem::GemcutterUtilities
27
+ class WebauthnListener
28
+ class Response
29
+ attr_reader :http_response
30
+
31
+ def self.for(host)
32
+ new(host)
33
+ end
34
+
35
+ def initialize(host)
36
+ @host = host
37
+
38
+ build_http_response
39
+ end
40
+
41
+ def to_s
42
+ status_line = "HTTP/#{@http_response.http_version} #{@http_response.code} #{@http_response.message}\r\n"
43
+ headers = @http_response.to_hash.map {|header, value| "#{header}: #{value.join(", ")}\r\n" }.join + "\r\n"
44
+ body = @http_response.body ? "#{@http_response.body}\n" : ""
45
+
46
+ status_line + headers + body
47
+ end
48
+
49
+ private
50
+
51
+ # Must be implemented in subclasses
52
+ def code
53
+ raise NotImplementedError
54
+ end
55
+
56
+ def reason_phrase
57
+ raise NotImplementedError
58
+ end
59
+
60
+ def body; end
61
+
62
+ def build_http_response
63
+ response_class = Net::HTTPResponse::CODE_TO_OBJ[code.to_s]
64
+ @http_response = response_class.new("1.1", code, reason_phrase)
65
+ @http_response.instance_variable_set(:@read, true)
66
+
67
+ add_connection_header
68
+ add_access_control_headers
69
+ add_body
70
+ end
71
+
72
+ def add_connection_header
73
+ @http_response["connection"] = "close"
74
+ end
75
+
76
+ def add_access_control_headers
77
+ @http_response["access-control-allow-origin"] = @host
78
+ @http_response["access-control-allow-methods"] = "POST"
79
+ @http_response["access-control-allow-headers"] = %w[Content-Type Authorization x-csrf-token]
80
+ end
81
+
82
+ def add_body
83
+ return unless body
84
+ @http_response["content-type"] = "text/plain; charset=utf-8"
85
+ @http_response["content-length"] = body.bytesize
86
+ @http_response.instance_variable_set(:@body, body)
87
+ end
88
+ end
89
+
90
+ class OkResponse < Response
91
+ private
92
+
93
+ def code
94
+ 200
95
+ end
96
+
97
+ def reason_phrase
98
+ "OK"
99
+ end
100
+
101
+ def body
102
+ "success"
103
+ end
104
+ end
105
+
106
+ class NoContentResponse < Response
107
+ private
108
+
109
+ def code
110
+ 204
111
+ end
112
+
113
+ def reason_phrase
114
+ "No Content"
115
+ end
116
+ end
117
+
118
+ class BadRequestResponse < Response
119
+ private
120
+
121
+ def code
122
+ 400
123
+ end
124
+
125
+ def reason_phrase
126
+ "Bad Request"
127
+ end
128
+
129
+ def body
130
+ "missing code parameter"
131
+ end
132
+ end
133
+
134
+ class NotFoundResponse < Response
135
+ private
136
+
137
+ def code
138
+ 404
139
+ end
140
+
141
+ def reason_phrase
142
+ "Not Found"
143
+ end
144
+ end
145
+
146
+ class MethodNotAllowedResponse < Response
147
+ private
148
+
149
+ def code
150
+ 405
151
+ end
152
+
153
+ def reason_phrase
154
+ "Method Not Allowed"
155
+ end
156
+
157
+ def add_access_control_headers
158
+ super
159
+ @http_response["allow"] = %w[GET OPTIONS]
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "webauthn_listener/response"
4
+
5
+ ##
6
+ # The WebauthnListener class retrieves an OTP after a user successfully WebAuthns with the Gem host.
7
+ # An instance opens a socket using the TCPServer instance given and listens for a request from the Gem host.
8
+ # The request should be a GET request to the root path and contains the OTP code in the form
9
+ # of a query parameter `code`. The listener will return the code which will be used as the OTP for
10
+ # API requests.
11
+ #
12
+ # Types of responses sent by the listener after receiving a request:
13
+ # - 200 OK: OTP code was successfully retrieved
14
+ # - 204 No Content: If the request was an OPTIONS request
15
+ # - 400 Bad Request: If the request did not contain a query parameter `code`
16
+ # - 404 Not Found: The request was not to the root path
17
+ # - 405 Method Not Allowed: OTP code was not retrieved because the request was not a GET/OPTIONS request
18
+ #
19
+ # Example usage:
20
+ #
21
+ # thread = Gem::WebauthnListener.listener_thread("https://rubygems.example", server)
22
+ # thread.join
23
+ # otp = thread[:otp]
24
+ # error = thread[:error]
25
+ #
26
+
27
+ module Gem::GemcutterUtilities
28
+ class WebauthnListener
29
+ attr_reader :host
30
+
31
+ def initialize(host)
32
+ @host = host
33
+ end
34
+
35
+ def self.listener_thread(host, server)
36
+ Thread.new do
37
+ thread = Thread.current
38
+ thread.abort_on_exception = true
39
+ thread.report_on_exception = false
40
+ thread[:otp] = new(host).wait_for_otp_code(server)
41
+ rescue Gem::WebauthnVerificationError => e
42
+ thread[:error] = e
43
+ ensure
44
+ server.close
45
+ end
46
+ end
47
+
48
+ def wait_for_otp_code(server)
49
+ loop do
50
+ socket = server.accept
51
+ request_line = socket.gets
52
+
53
+ method, req_uri, _protocol = request_line.split(" ")
54
+ req_uri = URI.parse(req_uri)
55
+
56
+ responder = SocketResponder.new(socket)
57
+
58
+ unless root_path?(req_uri)
59
+ responder.send(NotFoundResponse.for(host))
60
+ raise Gem::WebauthnVerificationError, "Page at #{req_uri.path} not found."
61
+ end
62
+
63
+ case method.upcase
64
+ when "OPTIONS"
65
+ responder.send(NoContentResponse.for(host))
66
+ next # will be GET
67
+ when "GET"
68
+ if otp = parse_otp_from_uri(req_uri)
69
+ responder.send(OkResponse.for(host))
70
+ return otp
71
+ end
72
+ responder.send(BadRequestResponse.for(host))
73
+ raise Gem::WebauthnVerificationError, "Did not receive OTP from #{host}."
74
+ else
75
+ responder.send(MethodNotAllowedResponse.for(host))
76
+ raise Gem::WebauthnVerificationError, "Invalid HTTP method #{method.upcase} received."
77
+ end
78
+ end
79
+ end
80
+
81
+ private
82
+
83
+ def root_path?(uri)
84
+ uri.path == "/"
85
+ end
86
+
87
+ def parse_otp_from_uri(uri)
88
+ require "cgi"
89
+
90
+ return if uri.query.nil?
91
+ CGI.parse(uri.query).dig("code", 0)
92
+ end
93
+
94
+ class SocketResponder
95
+ def initialize(socket)
96
+ @socket = socket
97
+ end
98
+
99
+ def send(response)
100
+ @socket.print response.to_s
101
+ @socket.close
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # The WebauthnPoller class retrieves an OTP after a user successfully WebAuthns. An instance
5
+ # polls the Gem host for the OTP code. The polling request (api/v1/webauthn_verification/<webauthn_token>/status.json)
6
+ # is sent to the Gem host every 5 seconds and will timeout after 5 minutes. If the status field in the json response
7
+ # is "success", the code field will contain the OTP code.
8
+ #
9
+ # Example usage:
10
+ #
11
+ # thread = Gem::WebauthnPoller.poll_thread(
12
+ # {},
13
+ # "RubyGems.org",
14
+ # "https://rubygems.org/api/v1/webauthn_verification/odow34b93t6aPCdY",
15
+ # { email: "email@example.com", password: "password" }
16
+ # )
17
+ # thread.join
18
+ # otp = thread[:otp]
19
+ # error = thread[:error]
20
+ #
21
+
22
+ module Gem::GemcutterUtilities
23
+ class WebauthnPoller
24
+ include Gem::GemcutterUtilities
25
+ TIMEOUT_IN_SECONDS = 300
26
+
27
+ attr_reader :options, :host
28
+
29
+ def initialize(options, host)
30
+ @options = options
31
+ @host = host
32
+ end
33
+
34
+ def self.poll_thread(options, host, webauthn_url, credentials)
35
+ Thread.new do
36
+ thread = Thread.current
37
+ thread.abort_on_exception = true
38
+ thread.report_on_exception = false
39
+ thread[:otp] = new(options, host).poll_for_otp(webauthn_url, credentials)
40
+ rescue Gem::WebauthnVerificationError, Timeout::Error => e
41
+ thread[:error] = e
42
+ end
43
+ end
44
+
45
+ def poll_for_otp(webauthn_url, credentials)
46
+ Timeout.timeout(TIMEOUT_IN_SECONDS) do
47
+ loop do
48
+ response = webauthn_verification_poll_response(webauthn_url, credentials)
49
+ raise Gem::WebauthnVerificationError, response.message unless response.is_a?(Net::HTTPSuccess)
50
+
51
+ require "json"
52
+ parsed_response = JSON.parse(response.body)
53
+ case parsed_response["status"]
54
+ when "pending"
55
+ sleep 5
56
+ when "success"
57
+ return parsed_response["code"]
58
+ else
59
+ raise Gem::WebauthnVerificationError, parsed_response.fetch("message", "Invalid response from server")
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def webauthn_verification_poll_response(webauthn_url, credentials)
68
+ webauthn_token = %r{(?<=\/)[^\/]+(?=$)}.match(webauthn_url)[0]
69
+ rubygems_api_request(:get, "api/v1/webauthn_verification/#{webauthn_token}/status.json") do |request|
70
+ if credentials.empty?
71
+ request.add_field "Authorization", api_key
72
+ else
73
+ request.basic_auth credentials[:email], credentials[:password]
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -1,6 +1,9 @@
1
1
  # frozen_string_literal: true
2
- require_relative 'remote_fetcher'
3
- require_relative 'text'
2
+
3
+ require_relative "remote_fetcher"
4
+ require_relative "text"
5
+ require_relative "gemcutter_utilities/webauthn_listener"
6
+ require_relative "gemcutter_utilities/webauthn_poller"
4
7
 
5
8
  ##
6
9
  # Utility methods for using the RubyGems API.
@@ -19,8 +22,8 @@ module Gem::GemcutterUtilities
19
22
  # Add the --key option
20
23
 
21
24
  def add_key_option
22
- add_option('-k', '--key KEYNAME', Symbol,
23
- 'Use the given API key',
25
+ add_option("-k", "--key KEYNAME", Symbol,
26
+ "Use the given API key",
24
27
  "from #{Gem.configuration.credentials_path}") do |value,options|
25
28
  options[:key] = value
26
29
  end
@@ -30,9 +33,9 @@ module Gem::GemcutterUtilities
30
33
  # Add the --otp option
31
34
 
32
35
  def add_otp_option
33
- add_option('--otp CODE',
34
- 'Digit code for multifactor authentication',
35
- 'You can also use the environment variable GEM_HOST_OTP_CODE') do |value, options|
36
+ add_option("--otp CODE",
37
+ "Digit code for multifactor authentication",
38
+ "You can also use the environment variable GEM_HOST_OTP_CODE") do |value, options|
36
39
  options[:otp] = value
37
40
  end
38
41
  end
@@ -69,9 +72,8 @@ module Gem::GemcutterUtilities
69
72
 
70
73
  @host ||=
71
74
  begin
72
- env_rubygems_host = ENV['RUBYGEMS_HOST']
73
- env_rubygems_host = nil if
74
- env_rubygems_host and env_rubygems_host.empty?
75
+ env_rubygems_host = ENV["RUBYGEMS_HOST"]
76
+ env_rubygems_host = nil if env_rubygems_host&.empty?
75
77
 
76
78
  env_rubygems_host || configured_host
77
79
  end
@@ -82,8 +84,8 @@ module Gem::GemcutterUtilities
82
84
  #
83
85
  # If +allowed_push_host+ metadata is present, then it will only allow that host.
84
86
 
85
- def rubygems_api_request(method, path, host = nil, allowed_push_host = nil, scope: nil, &block)
86
- require 'net/http'
87
+ def rubygems_api_request(method, path, host = nil, allowed_push_host = nil, scope: nil, credentials: {}, &block)
88
+ require "net/http"
87
89
 
88
90
  self.host = host if host
89
91
  unless self.host
@@ -105,7 +107,7 @@ module Gem::GemcutterUtilities
105
107
  response = request_with_otp(method, uri, &block)
106
108
 
107
109
  if mfa_unauthorized?(response)
108
- ask_otp
110
+ fetch_otp(credentials)
109
111
  response = request_with_otp(method, uri, &block)
110
112
  end
111
113
 
@@ -118,7 +120,7 @@ module Gem::GemcutterUtilities
118
120
  end
119
121
 
120
122
  def mfa_unauthorized?(response)
121
- response.kind_of?(Net::HTTPUnauthorized) && response.body.start_with?('You have enabled multifactor authentication')
123
+ response.kind_of?(Net::HTTPUnauthorized) && response.body.start_with?("You have enabled multifactor authentication")
122
124
  end
123
125
 
124
126
  def update_scope(scope)
@@ -163,11 +165,16 @@ module Gem::GemcutterUtilities
163
165
 
164
166
  key_name = get_key_name(scope)
165
167
  scope_params = get_scope_params(scope)
166
- mfa_params = get_mfa_params(email, password)
168
+ profile = get_user_profile(email, password)
169
+ mfa_params = get_mfa_params(profile)
167
170
  all_params = scope_params.merge(mfa_params)
171
+ warning = profile["warning"]
172
+ credentials = { email: email, password: password }
173
+
174
+ say "#{warning}\n" if warning
168
175
 
169
176
  response = rubygems_api_request(:post, "api/v1/api_key",
170
- sign_in_host, scope: scope) do |request|
177
+ sign_in_host, credentials: credentials, scope: scope) do |request|
171
178
  request.basic_auth email, password
172
179
  request["OTP"] = otp if otp
173
180
  request.body = URI.encode_www_form({ name: key_name }.merge(all_params))
@@ -197,7 +204,8 @@ module Gem::GemcutterUtilities
197
204
  # block was given or shows the response body to the user.
198
205
  #
199
206
  # If the response was not successful, shows an error to the user including
200
- # the +error_prefix+ and the response body.
207
+ # the +error_prefix+ and the response body. If the response was a permanent redirect,
208
+ # shows an error to the user including the redirect location.
201
209
 
202
210
  def with_response(response, error_prefix = nil)
203
211
  case response
@@ -207,6 +215,12 @@ module Gem::GemcutterUtilities
207
215
  else
208
216
  say clean_text(response.body)
209
217
  end
218
+ when Net::HTTPPermanentRedirect, Net::HTTPRedirection then
219
+ message = "The request has redirected permanently to #{response['location']}. Please check your defined push host URL."
220
+ message = "#{error_prefix}: #{message}" if error_prefix
221
+
222
+ say clean_text(message)
223
+ terminate_interaction(ERROR_CODE)
210
224
  else
211
225
  message = response.body
212
226
  message = "#{error_prefix}: #{message}" if error_prefix
@@ -239,14 +253,57 @@ module Gem::GemcutterUtilities
239
253
  end
240
254
  end
241
255
 
242
- def ask_otp
243
- say 'You have enabled multi-factor authentication. Please enter OTP code.'
244
- options[:otp] = ask 'Code: '
256
+ def fetch_otp(credentials)
257
+ options[:otp] = if webauthn_url = webauthn_verification_url(credentials)
258
+ server = TCPServer.new 0
259
+ port = server.addr[1].to_s
260
+
261
+ url_with_port = "#{webauthn_url}?port=#{port}"
262
+ say "You have enabled multi-factor authentication. Please visit #{url_with_port} to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin command with the `--otp [your_code]` option."
263
+
264
+ threads = [WebauthnListener.listener_thread(host, server), WebauthnPoller.poll_thread(options, host, webauthn_url, credentials)]
265
+ otp_thread = wait_for_otp_thread(*threads)
266
+
267
+ threads.each(&:join)
268
+
269
+ if error = otp_thread[:error]
270
+ alert_error error.message
271
+ terminate_interaction(1)
272
+ end
273
+
274
+ say "You are verified with a security device. You may close the browser window."
275
+ otp_thread[:otp]
276
+ else
277
+ say "You have enabled multi-factor authentication. Please enter OTP code."
278
+ ask "Code: "
279
+ end
280
+ end
281
+
282
+ def wait_for_otp_thread(*threads)
283
+ loop do
284
+ threads.each do |otp_thread|
285
+ return otp_thread unless otp_thread.alive?
286
+ end
287
+ sleep 0.1
288
+ end
289
+ ensure
290
+ threads.each(&:exit)
291
+ end
292
+
293
+ def webauthn_verification_url(credentials)
294
+ response = rubygems_api_request(:post, "api/v1/webauthn_verification") do |request|
295
+ if credentials.empty?
296
+ request.add_field "Authorization", api_key
297
+ else
298
+ request.basic_auth credentials[:email], credentials[:password]
299
+ end
300
+ end
301
+ response.is_a?(Net::HTTPSuccess) ? response.body : nil
245
302
  end
246
303
 
247
304
  def pretty_host(host)
248
305
  if default_host?
249
- 'RubyGems.org'
306
+ "RubyGems.org"
250
307
  else
251
308
  host
252
309
  end
@@ -273,27 +330,26 @@ module Gem::GemcutterUtilities
273
330
  self.host == Gem::DEFAULT_HOST
274
331
  end
275
332
 
276
- def get_mfa_params(email, password)
333
+ def get_user_profile(email, password)
277
334
  return {} unless default_host?
278
335
 
279
- mfa_level = get_user_mfa_level(email, password)
280
- params = {}
281
- if mfa_level == "ui_only" || mfa_level == "ui_and_gem_signin"
282
- selected = ask_yes_no("Would you like to enable MFA for this key? (strongly recommended)")
283
- params["mfa"] = true if selected
284
- end
285
- params
286
- end
287
-
288
- def get_user_mfa_level(email, password)
289
336
  response = rubygems_api_request(:get, "api/v1/profile/me.yaml") do |request|
290
337
  request.basic_auth email, password
291
338
  end
292
339
 
293
340
  with_response response do |resp|
294
- body = Gem::SafeYAML.load clean_text(resp.body)
295
- body["mfa"]
341
+ Gem::SafeYAML.load clean_text(resp.body)
342
+ end
343
+ end
344
+
345
+ def get_mfa_params(profile)
346
+ mfa_level = profile["mfa"]
347
+ params = {}
348
+ if mfa_level == "ui_only" || mfa_level == "ui_and_gem_signin"
349
+ selected = ask_yes_no("Would you like to enable MFA for this key? (strongly recommended)")
350
+ params["mfa"] = true if selected
296
351
  end
352
+ params
297
353
  end
298
354
 
299
355
  def get_key_name(scope)