diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 6341d8282a4..008f1e01d91 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - - uses: ruby/setup-ruby@d5fb7a202fc07872cb44f00ba8e6197b70cb0c55 # v1.179.0 + - uses: ruby/setup-ruby@ff740bc00a01b3a50fffc55a1071b1060eeae9dc # v1.180.0 with: bundler-cache: true - name: Rubocop @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - - uses: ruby/setup-ruby@d5fb7a202fc07872cb44f00ba8e6197b70cb0c55 # v1.179.0 + - uses: ruby/setup-ruby@ff740bc00a01b3a50fffc55a1071b1060eeae9dc # v1.180.0 with: bundler-cache: true - name: Brakeman @@ -33,7 +33,7 @@ jobs: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - - uses: ruby/setup-ruby@d5fb7a202fc07872cb44f00ba8e6197b70cb0c55 # v1.179.0 + - uses: ruby/setup-ruby@ff740bc00a01b3a50fffc55a1071b1060eeae9dc # v1.180.0 with: bundler-cache: true - name: Importmap Verify @@ -51,7 +51,7 @@ jobs: - name: login to Github Packages run: echo "${{ github.token }}" | docker login https://ghcr.io -u ${GITHUB_ACTOR} --password-stdin - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - - uses: ruby/setup-ruby@d5fb7a202fc07872cb44f00ba8e6197b70cb0c55 # v1.179.0 + - uses: ruby/setup-ruby@ff740bc00a01b3a50fffc55a1071b1060eeae9dc # v1.180.0 with: bundler-cache: true - name: krane render diff --git a/Gemfile b/Gemfile index 1ae6e09b36b..cdc170e55c1 100644 --- a/Gemfile +++ b/Gemfile @@ -5,7 +5,7 @@ ruby file: ".ruby-version" gem "rails", "~> 7.1.0", ">= 7.1.3.2" gem "rails-i18n", "~> 7.0" gem "aws-sdk-s3", "~> 1.152" -gem "aws-sdk-sqs", "~> 1.75" +gem "aws-sdk-sqs", "~> 1.76" gem "bootsnap", "~> 1.18" gem "clearance", "~> 2.7" gem "dalli", "~> 3.2" @@ -20,9 +20,9 @@ gem "high_voltage", "~> 3.1" gem "honeybadger", "~> 5.5.1" # see https://github.com/rubygems/rubygems.org/pull/4598 gem "http_accept_language", "~> 2.1" gem "kaminari", "~> 1.2" -gem "launchdarkly-server-sdk", "~> 8.4" +gem "launchdarkly-server-sdk", "~> 8.5" gem "mail", "~> 2.8" -gem "octokit", "~> 8.1" +gem "octokit", "~> 9.1" gem "omniauth-github", "~> 2.0" gem "omniauth", "~> 2.1" gem "omniauth-rails_csrf_protection", "~> 1.0" diff --git a/Gemfile.lock b/Gemfile.lock index ef7b42527a6..8273c19c7b9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -110,7 +110,7 @@ GEM zeitwerk (>= 2.6.2) awrence (1.2.1) aws-eventstream (1.3.0) - aws-partitions (1.940.0) + aws-partitions (1.942.0) aws-sdk-core (3.197.0) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) @@ -119,11 +119,11 @@ GEM aws-sdk-kms (1.83.0) aws-sdk-core (~> 3, >= 3.197.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.152.0) + aws-sdk-s3 (1.152.1) aws-sdk-core (~> 3, >= 3.197.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.8) - aws-sdk-sqs (1.75.0) + aws-sdk-sqs (1.76.0) aws-sdk-core (~> 3, >= 3.197.0) aws-sigv4 (~> 1.1) aws-sigv4 (1.8.0) @@ -142,7 +142,7 @@ GEM brakeman (6.1.2) racc browser (6.0.0) - builder (3.2.4) + builder (3.3.0) byebug (11.1.3) capybara (3.40.0) addressable @@ -168,7 +168,7 @@ GEM railties (>= 5.0) coderay (1.1.3) compact_index (0.15.0) - concurrent-ruby (1.3.1) + concurrent-ruby (1.3.3) connection_pool (2.4.1) cose (1.3.0) cbor (~> 0.5.9) @@ -261,7 +261,7 @@ GEM fugit (>= 1.1) railties (>= 6.0.0) thor (>= 0.14.1) - google-protobuf (4.27.0) + google-protobuf (4.27.1) bigdecimal rake (>= 13) gravtastic (3.2.6) @@ -281,7 +281,7 @@ GEM http-cookie (~> 1.0) http-form_data (~> 2.2) llhttp-ffi (~> 0.5.0) - http-cookie (1.0.5) + http-cookie (1.0.6) domain_name (~> 0.5) http-form_data (2.3.0) http_accept_language (2.1.1) @@ -303,7 +303,7 @@ GEM rdoc (>= 4.0.0) reline (>= 0.4.2) jmespath (1.6.2) - job-iteration (1.4.1) + job-iteration (1.5.1) activejob (>= 5.2) json (2.7.2) json-jwt (1.16.6) @@ -327,7 +327,7 @@ GEM kaminari-core (= 1.2.2) kaminari-core (1.2.2) language_server-protocol (3.17.0.3) - launchdarkly-server-sdk (8.4.2) + launchdarkly-server-sdk (8.5.0) concurrent-ruby (~> 1.1) http (>= 4.4.0, < 6.0.0) json (~> 2.3) @@ -376,10 +376,11 @@ GEM net-imap net-pop net-smtp - maintenance_tasks (2.7.0) + maintenance_tasks (2.7.1) actionpack (>= 6.0) activejob (>= 6.0) activerecord (>= 6.0) + csv job-iteration (>= 1.3.6) railties (>= 6.0) zeitwerk (>= 2.6.2) @@ -432,8 +433,7 @@ GEM snaky_hash (~> 2.0) version_gem (~> 1.1) observer (0.1.2) - octokit (8.1.0) - base64 + octokit (9.1.0) faraday (>= 1, < 3) sawyer (~> 0.9) omniauth (2.1.2) @@ -678,7 +678,7 @@ GEM sprockets (4.2.1) concurrent-ruby (~> 1.0) rack (>= 2.2.4, < 4) - sprockets-rails (3.5.0) + sprockets-rails (3.5.1) actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) @@ -696,7 +696,7 @@ GEM faraday-follow_redirects tailwindcss-rails (2.6.1) railties (>= 7.0.0) - terser (1.2.2) + terser (1.2.3) execjs (>= 0.3.0, < 3) thor (1.3.1) tilt (2.3.0) @@ -772,7 +772,7 @@ DEPENDENCIES autoprefixer-rails (~> 10.4) avo (~> 2.51) aws-sdk-s3 (~> 1.152) - aws-sdk-sqs (~> 1.75) + aws-sdk-sqs (~> 1.76) bcrypt (~> 3.1) bootsnap (~> 1.18) brakeman (~> 6.1) @@ -802,7 +802,7 @@ DEPENDENCIES http_accept_language (~> 2.1) importmap-rails (~> 2.0) kaminari (~> 1.2) - launchdarkly-server-sdk (~> 8.4) + launchdarkly-server-sdk (~> 8.5) launchy (~> 3.0) letter_opener (~> 1.10) letter_opener_web (~> 3.0) @@ -817,7 +817,7 @@ DEPENDENCIES minitest-retry (~> 0.2.2) mocha (~> 2.3) observer (~> 0.1.2) - octokit (~> 8.1) + octokit (~> 9.1) omniauth (~> 2.1) omniauth-github (~> 2.0) omniauth-rails_csrf_protection (~> 1.0) @@ -903,11 +903,11 @@ CHECKSUMS avo (2.51.0) sha256=0d5785cda01b5b0d2575e7419cda4dc7a5d7805068f160d48ecc7458ee74ec03 awrence (1.2.1) sha256=dd1d214c12a91f449d1ef81d7ee3babc2816944e450752e7522c65521872483e aws-eventstream (1.3.0) sha256=f1434cc03ab2248756eb02cfa45e900e59a061d7fbdc4a9fd82a5dd23d796d3f - aws-partitions (1.940.0) sha256=ee8561e842a40755ed485970a0c7c1598f48a4b2516593cec45f72e2408c8f14 + aws-partitions (1.942.0) sha256=31ad735545bdbeaefbeb15c5f828115bfb17d261dccc25d79d0df16b36804386 aws-sdk-core (3.197.0) sha256=34c44883d3cc91ada382f6ecab981a1b7ede9a1ec47cf8eb2eaa3ee46035db90 aws-sdk-kms (1.83.0) sha256=1c9c875a52bd36e62828aae454c3f42b77a61b118d8414ee66dbbe0c69ec16bf - aws-sdk-s3 (1.152.0) sha256=f502f292b691ea45db0b4ac8f04ff54ed5625d647340f93c7e1b4a91ea08d720 - aws-sdk-sqs (1.75.0) sha256=b5895960a731acc2284dee9aefe63e3989d0ca4f506706712aff303e00680b9a + aws-sdk-s3 (1.152.1) sha256=15abb58452e91139b05ac808da6a9eea42070eb42d1fa31b95d1fbd23167be22 + aws-sdk-sqs (1.76.0) sha256=926253c2bf7717394ced3138cd7661dea1a54fc1868456e82042102c4ba16139 aws-sigv4 (1.8.0) sha256=84dd99768b91b93b63d1d8e53ee837cfd06ab402812772a7899a78f9f9117cbc base64 (0.2.0) sha256=0f25e9b21a02a0cc0cea8ef92b2041035d39350946e8789c562b2d1a3da01507 bcrypt (3.1.20) sha256=8410f8c7b3ed54a3c00cd2456bf13917d695117f033218e2483b2e40b0784099 @@ -919,7 +919,7 @@ CHECKSUMS bootsnap (1.18.3) sha256=d7b70de761e2fb1d63d21dd941b393c881c5cab5575211369cede788dfc034eb brakeman (6.1.2) sha256=7716769c18f2c4a52d7a74d2cb5a614be0c46d8aad3fbe7ca089dbb7c98bd4d3 browser (6.0.0) sha256=0399f0f12c925e529aa995b096a3824384e00ea2c7241fbb4b707d2a25e87920 - builder (3.2.4) sha256=99caf08af60c8d7f3a6b004029c4c3c0bdaebced6c949165fe98f1db27fbbc10 + builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f byebug (11.1.3) sha256=2485944d2bb21283c593d562f9ae1019bf80002143cc3a255aaffd4e9cf4a35b capybara (3.40.0) sha256=42dba720578ea1ca65fd7a41d163dd368502c191804558f6e0f71b391054aeef cbor (0.5.9.8) sha256=9ee097fc58d9bc5e406d112cd2d4e112c7354ec16f8b6ff34e4732c1e44b4eb7 @@ -930,7 +930,7 @@ CHECKSUMS clearance (2.7.1) sha256=6604beacb8abe4ba939da41491148d8ff965f4484bba946bb50a61be61683f0d coderay (1.1.3) sha256=dc530018a4684512f8f38143cd2a096c9f02a1fc2459edcfe534787a7fc77d4b compact_index (0.15.0) sha256=5c6c404afca8928a7d9f4dde9524f6e1610db17e675330803055db282da84a8b - concurrent-ruby (1.3.1) sha256=c369f1d0875b42295fe0fabc321065f3cfeab8c32c526c01b6b05af1efc8b0ce + concurrent-ruby (1.3.3) sha256=4f9cd28965c4dcf83ffd3ea7304f9323277be8525819cb18a3b61edcb56a7c6a connection_pool (2.4.1) sha256=0f40cf997091f1f04ff66da67eabd61a9fe0d4928b9a3645228532512fab62f4 cose (1.3.0) sha256=63247c66a5bc76e53926756574fe3724cc0a88707e358c90532ae2a320e98601 crack (1.0.0) sha256=c83aefdb428cdc7b66c7f287e488c796f055c0839e6e545fec2c7047743c4a49 @@ -970,7 +970,7 @@ CHECKSUMS get_process_mem (0.2.7) sha256=4afd3c3641dd6a817c09806c7d6d509d8a9984512ac38dea8b917426bbf77eba globalid (1.2.1) sha256=70bf76711871f843dbba72beb8613229a49429d1866828476f9c9d6ccc327ce9 good_job (3.29.3) sha256=9ee44573af5195068d57078627c1e7a9b2bd415412f7efe13a228f04fe507d73 - google-protobuf (4.27.0) sha256=5e679347abc4721a3346913b8f69640a4ee13e0105d605b1da226b25346cd88d + google-protobuf (4.27.1) sha256=a988ba32cbb4a85c2340e4840dd3e88874225b54f23f7432dedea6ae25695578 gravtastic (3.2.6) sha256=ef98abcecf7c402b61cff1ae7c50a2c6d97dd22bac21ea9b421ce05bc03d734f groupdate (6.4.0) sha256=65940645bf2a48f9b2d10ab7a1d19bdc78f3c89559d8fce39cea3448a15aec54 hashdiff (1.1.0) sha256=b5465f0e7375f1ee883f53a766ece4dbc764b7674a7c5ffd76e79b2f5f6fc9c9 @@ -981,7 +981,7 @@ CHECKSUMS htmlbeautifier (1.4.3) sha256=b43d08f7e2aa6ae1b5a6f0607b4ed8954c8d4a8e85fd2336f975dda1e4db385b htmlentities (4.3.4) sha256=125a73c6c9f2d1b62100b7c3c401e3624441b663762afa7fe428476435a673da http (5.2.0) sha256=b99ed3c65376e0fd8107647fbaf5a8ab4f66c347d1271fb74cea757e209c6115 - http-cookie (1.0.5) sha256=73756d46c7dbdc7023deecdb8a171348ea95a1b99810b31cfe8b4fb4e9a6318f + http-cookie (1.0.6) sha256=7713d3196f21ff5ab0944011d7d4e619b62ec082374a52de2193ccfe78924044 http-form_data (2.3.0) sha256=cc4eeb1361d9876821e31d7b1cf0b68f1cf874b201d27903480479d86448a5f3 http_accept_language (2.1.1) sha256=0043f0d55a148cf45b604dbdd197cb36437133e990016c68c892d49dbea31634 httparty (0.22.0) sha256=78652a5c9471cf0093d3b2083c2295c9c8f12b44c65112f1846af2b71430fa6c @@ -991,7 +991,7 @@ CHECKSUMS io-console (0.7.2) sha256=f0dccff252f877a4f60d04a4dc6b442b185ebffb4b320ab69212a92b48a7a221 irb (1.13.1) sha256=aa552f30b33f15615cff4ca8d04bace0bdd442777efb5187d9a621707889f292 jmespath (1.6.2) sha256=238d774a58723d6c090494c8879b5e9918c19485f7e840f2c1c7532cf84ebcb1 - job-iteration (1.4.1) sha256=7243c40e4decc3d49529867e9c504afaea332976c967ffdebed9ff863c6424af + job-iteration (1.5.1) sha256=1428ad5b308adbaae8776c16b7792a846eb1ad7f4ab3c6e0f9668dd2ab1179e5 json (2.7.2) sha256=1898b5cbc81cd36c0fd4d0b7ad2682c39fb07c5ff682fc6265f678f550d4982c json-jwt (1.16.6) sha256=ab451f9cd8743cecc4137f4170806046c1d8a6d4ee6e8570e0b5c958409b266c jwt (2.7.1) sha256=07357cd2f180739b2f8184eda969e252d850ac996ed0a23f616e8ff0a90ae19b @@ -1000,7 +1000,7 @@ CHECKSUMS kaminari-activerecord (1.2.2) sha256=0dd3a67bab356a356f36b3b7236bcb81cef313095365befe8e98057dd2472430 kaminari-core (1.2.2) sha256=3bd26fec7370645af40ca73b9426a448d09b8a8ba7afa9ba3c3e0d39cdbb83ff language_server-protocol (3.17.0.3) sha256=3d5c58c02f44a20d972957a9febe386d7e7468ab3900ce6bd2b563dd910c6b3f - launchdarkly-server-sdk (8.4.2) sha256=36cdf34777f80687ee34acd0bd563b00153f4b24fe12be5eff15c4708be65ec3 + launchdarkly-server-sdk (8.5.0) sha256=5c286fb97b7e68996e9bfe2688ce0e1c5bdc092980b84934746e2e3668367de0 launchy (3.0.1) sha256=b7fa60bda0197cf57614e271a250a8ca1f6a34ab889a3c73f67ec5d57c8a7f2c ld-eventsource (2.2.2) sha256=5ea087a6f06bbd8e325d2c1aaead50f37f13d025b952985739e9380a78a96beb letter_opener (1.10.0) sha256=2ff33f2e3b5c3c26d1959be54b395c086ca6d44826e8bf41a14ff96fdf1bdbb2 @@ -1012,7 +1012,7 @@ CHECKSUMS loofah (2.22.0) sha256=10d76e070c86b12fec74b6a9515fd1940f4459198b991342d0a7897d86c372fe lookbook (2.3.1) sha256=d6ba294f3bd2fe8c39c30530a12aa99d42d202a5d6bff3d3edcafd6d2978dc39 mail (2.8.1) sha256=ec3b9fadcf2b3755c78785cb17bc9a0ca9ee9857108a64b6f5cfc9c0b5bfc9ad - maintenance_tasks (2.7.0) sha256=0857d732e6c3078a501a1552d0ffb6321c900dc821c15bf09b6457931d6ccbcb + maintenance_tasks (2.7.1) sha256=2f1f42239a11f5b30ef34e821f1beb42010d08e81634d8945884aba8bdb982db marcel (1.0.4) sha256=0d5649feb64b8f19f3d3468b96c680bae9746335d02194270287868a661516a4 matrix (0.4.2) sha256=71083ccbd67a14a43bfa78d3e4dc0f4b503b9cc18e5b4b1d686dc0f9ef7c4cc0 memory_profiler (1.0.1) sha256=38cdb42f22d9100df2eba0365c199724b58b05c38e765cd764a07392916901b1 @@ -1039,7 +1039,7 @@ CHECKSUMS nokogiri (1.16.5) sha256=ec36162c68984fa0a90a5c4ae7ab7759460639e716cc1ce75f34c3cb54158ad2 oauth2 (2.0.9) sha256=b21f9defcf52dc1610e0dfab4c868342173dcd707fd15c777d9f4f04e153f7fb observer (0.1.2) sha256=d8a3107131ba661138d748e7be3dbafc0d82e732fffba9fccb3d7829880950ac - octokit (8.1.0) sha256=82229ce9b54e910e27ae75ff21e54bc97072913b5af06750999966e6817af8cd + octokit (9.1.0) sha256=7849a659d2722c629181f48d1d7e567c9539f1a85c9676144dbdbfc6ce288253 omniauth (2.1.2) sha256=def03277298b8f8a5d3ff16cdb2eb5edb9bffed60ee7dda24cc0c89b3ae6a0ce omniauth-github (2.0.1) sha256=8ff8e70ac6d6db9d52485eef52cfa894938c941496e66b52b5e2773ade3ccad4 omniauth-oauth2 (1.8.0) sha256=b2f8e9559cc7e2d4efba57607691d6d2b634b879fc5b5b6ccfefa3da85089e78 @@ -1131,7 +1131,7 @@ CHECKSUMS simplecov_json_formatter (0.1.4) sha256=529418fbe8de1713ac2b2d612aa3daa56d316975d307244399fa4838c601b428 snaky_hash (2.0.1) sha256=1ac87ec157fcfe7a460e821e0cd48ae1e6f5e3e082ab520f03f31a9259dbdc31 sprockets (4.2.1) sha256=951b13dd2f2fcae840a7184722689a803e0ff9d2702d902bd844b196da773f97 - sprockets-rails (3.5.0) sha256=9d26058fe90d0f47fdaac13c0059110d5f959c08c4f90e8dd4cb34b3d90f2003 + sprockets-rails (3.5.1) sha256=c44626cb3887a1a8b572ca258685db33b4ebd041aa73428a716eac444ee5ef48 statsd-instrument (3.7.0) sha256=071eb94be7af7f529da45528ab4e3d96976fcdc8f4afd198ef2057b6b7987491 stimulus-rails (1.3.3) sha256=4d1f9ab1d64e605f4c9cdd4cc530a9538b510606d32d02249d106256845c562c stringio (3.1.0) sha256=c1f6263ae03a15025e51194ab19b06b15e06adcaaedb7f5f6c06ab60f5d67718 @@ -1139,7 +1139,7 @@ CHECKSUMS strscan (3.1.0) sha256=01b8a81d214fbf7b5308c6fb51b5972bbfc4a6aa1f166fd3618ba97e0fcd5555 swd (2.0.3) sha256=4cdbe2a4246c19f093fce22e967ec3ebdd4657d37673672e621bf0c7eb770655 tailwindcss-rails (2.6.1) sha256=60e66e243761402f9ce834132f59dd6c08b6fea5987e321bd9886dd0b0ce04ac - terser (1.2.2) sha256=86ddfa0de7fa8f6c8fd34ad611596f787a77e21bed3db08b90e7c30942d20288 + terser (1.2.3) sha256=c03111b9b01a7e70cd456b5d9aedf0a56fb99314a19311c4278c01ccebe3da9c thor (1.3.1) sha256=fa7e3471d4f6a27138e3d9c9b0d4daac9c3d7383927667ae83e9ab42ae7401ef tilt (2.3.0) sha256=82dd903d61213c63679d28e404ee8e10d1b0fdf5270f1ad0898ec314cc3e745c timeout (0.4.1) sha256=6f1f4edd4bca28cffa59501733a94215407c6960bd2107331f0280d4abdebb9a diff --git a/app/controllers/multifactor_auths_controller.rb b/app/controllers/multifactor_auths_controller.rb index 3d4c73ad2aa..f90bb4d27b6 100644 --- a/app/controllers/multifactor_auths_controller.rb +++ b/app/controllers/multifactor_auths_controller.rb @@ -167,6 +167,6 @@ def otp_verification_url end def webauthn_verification_url - setup_webauthn_authentication(form_url: webauthn_update_multifactor_auth_url(token: current_user.confirmation_token)) + webauthn_update_multifactor_auth_url(token: current_user.confirmation_token) end end diff --git a/config/initializers/datadog.rb b/config/initializers/datadog.rb index be8dd1f2ec3..83a0658d1fd 100644 --- a/config/initializers/datadog.rb +++ b/config/initializers/datadog.rb @@ -31,6 +31,11 @@ c.diagnostics.startup_logs.enabled = false end + c.tags = { + "git.commit.sha" => AppRevision.version, + "git.repository_url" => "https://github.com/rubygems/rubygems.org" + } + # Configuring the datadog library c.logger.instance = SemanticLogger[Datadog] diff --git a/test/system/multifactor_auths_test.rb b/test/system/multifactor_auths_test.rb index f824df9501c..37d82e5a15f 100644 --- a/test/system/multifactor_auths_test.rb +++ b/test/system/multifactor_auths_test.rb @@ -3,122 +3,165 @@ class MultifactorAuthsTest < ApplicationSystemTestCase setup do @user = create(:user, email: "testuser@example.com", password: PasswordHelpers::SECURE_TEST_PASSWORD, handle: "testuser") - @rubygem = create(:rubygem) - create(:ownership, rubygem: @rubygem, user: @user) - GemDownload.increment( - Rubygem::MFA_REQUIRED_THRESHOLD + 1, - rubygem_id: @rubygem.id - ) @seed = ROTP::Base32.random_base32 @totp = ROTP::TOTP.new(@seed) end teardown do @user.disable_totp! + @authenticator&.remove! + Capybara.reset_sessions! + Capybara.use_default_driver end - test "setup mfa does not cache OTP setup" do - sign_in - visit edit_settings_path + context "cache-control" do + should "setup mfa does not cache OTP setup" do + sign_in - click_button "Register a new device" - saved_otp_key = otp_key - totp = ROTP::TOTP.new(saved_otp_key) - fill_in "otp", with: totp.now - click_button "Enable" + register_otp_device - assert page.has_content? "Recovery codes" + assert page.has_content? "Recovery codes" - go_back + go_back - assert page.has_content? "has already been enabled" - refute page.has_content? "Register a new device" - refute page.has_content? saved_otp_key - end + assert page.has_content? "has already been enabled" + refute page.has_content? "Register a new device" + refute page.has_content? @otp_key + end - test "setup mfa does not cache recovery codes" do - sign_in - visit edit_settings_path + should "setup mfa does not cache recovery codes" do + sign_in - click_button "Register a new device" - totp = ROTP::TOTP.new(otp_key) - fill_in "otp", with: totp.now - click_button "Enable" + register_otp_device - assert page.has_content? "Recovery codes" - click_link "[ copy ]" - check "ack" - click_button "Continue" + assert page.has_content? "Recovery codes" + click_link "[ copy ]" + check "ack" + click_button "Continue" - go_back + go_back - refute page.has_content? "Recovery codes" + refute page.has_content? "Recovery codes" + end end - test "user with mfa disabled gets redirected back to adoptions after setting up mfa" do - redirect_test_mfa_disabled(adoptions_profile_path) - end + context "strong mfa required" do + setup do + @rubygem = create(:rubygem) + create(:ownership, rubygem: @rubygem, user: @user) + GemDownload.increment( + Rubygem::MFA_REQUIRED_THRESHOLD + 1, + rubygem_id: @rubygem.id + ) + end - test "user with mfa disabled gets redirected back to dashboard pages after setting up mfa" do - redirect_test_mfa_disabled(dashboard_path) - end + context "with mfa disabled" do + should "user with mfa disabled gets redirected back to adoptions after setting up mfa" do + redirect_test_mfa_disabled(adoptions_profile_path) + end - test "user with mfa disabled gets redirected back to delete profile pages after setting up mfa" do - redirect_test_mfa_disabled(delete_profile_path) - end + should "user with mfa disabled gets redirected back to dashboard pages after setting up mfa" do + redirect_test_mfa_disabled(dashboard_path) + end - test "user with mfa disabled gets redirected back to edit profile pages after setting up mfa" do - redirect_test_mfa_disabled(edit_profile_path) - end + should "user with mfa disabled gets redirected back to delete profile pages after setting up mfa" do + redirect_test_mfa_disabled(delete_profile_path) + end - test "user with mfa disabled gets redirected back to new api keys pages after setting up mfa" do - redirect_test_mfa_disabled(new_profile_api_key_path) { verify_password } - end + should "user with mfa disabled gets redirected back to edit profile pages after setting up mfa" do + redirect_test_mfa_disabled(edit_profile_path) + end - test "user with mfa disabled gets redirected back to notifier pages after setting up mfa" do - redirect_test_mfa_disabled(notifier_path) - end + should "user with mfa disabled gets redirected back to new api keys pages after setting up mfa" do + redirect_test_mfa_disabled(new_profile_api_key_path) { verify_password } + end - test "user with mfa disabled gets redirected back to profile api keys pages after setting up mfa" do - create(:api_key, scopes: %i[push_rubygem], owner: @user, ownership: @ownership) - redirect_test_mfa_disabled(profile_api_keys_path) { verify_password } - end + should "user with mfa disabled gets redirected back to notifier pages after setting up mfa" do + redirect_test_mfa_disabled(notifier_path) + end - test "user with mfa disabled gets redirected back to verify session pages after setting up mfa" do - redirect_test_mfa_disabled(verify_session_path) - end + should "user with mfa disabled gets redirected back to profile api keys pages after setting up mfa" do + create(:api_key, scopes: %i[push_rubygem], owner: @user, ownership: @ownership) + redirect_test_mfa_disabled(profile_api_keys_path) { verify_password } + end - test "user with weak level mfa gets redirected back to adoptions after setting up mfa" do - redirect_test_mfa_weak_level(adoptions_profile_path) - end + should "user with mfa disabled gets redirected back to verify session pages after setting up mfa" do + redirect_test_mfa_disabled(verify_session_path) + end + end - test "user with weak level mfa gets redirected back to dashboard pages after setting up mfa" do - redirect_test_mfa_weak_level(dashboard_path) - end + context "with weak level mfa" do + should "user gets redirected back to adoptions after setting up mfa" do + redirect_test_mfa_weak_level(adoptions_profile_path) + end - test "user with weak level mfa gets redirected back to delete profile pages after setting up mfa" do - redirect_test_mfa_weak_level(delete_profile_path) - end + should "user gets redirected back to dashboard pages after setting up mfa" do + redirect_test_mfa_weak_level(dashboard_path) + end - test "user with weak level mfa gets redirected back to edit profile pages after setting up mfa" do - redirect_test_mfa_weak_level(edit_profile_path) - end + should "user gets redirected back to delete profile pages after setting up mfa" do + redirect_test_mfa_weak_level(delete_profile_path) + end - test "user with weak level mfa gets redirected back to new api keys pages after setting up mfa" do - redirect_test_mfa_weak_level(new_profile_api_key_path) { verify_password } - end + should "user gets redirected back to edit profile pages after setting up mfa" do + redirect_test_mfa_weak_level(edit_profile_path) + end - test "user with weak level mfa gets redirected back to notifier pages after setting up mfa" do - redirect_test_mfa_weak_level(notifier_path) - end + should "user gets redirected back to new api keys pages after setting up mfa" do + redirect_test_mfa_weak_level(new_profile_api_key_path) { verify_password } + end - test "user with weak level mfa gets redirected back to profile api keys pages after setting up mfa" do - create(:api_key, scopes: %i[push_rubygem], owner: @user, ownership: @ownership) - redirect_test_mfa_weak_level(profile_api_keys_path) { verify_password } + should "user gets redirected back to notifier pages after setting up mfa" do + redirect_test_mfa_weak_level(notifier_path) + end + + should "user gets redirected back to profile api keys pages after setting up mfa" do + create(:api_key, scopes: %i[push_rubygem], owner: @user, ownership: @ownership) + redirect_test_mfa_weak_level(profile_api_keys_path) { verify_password } + end + + should "user gets redirected back to verify session pages after setting up mfa" do + redirect_test_mfa_weak_level(verify_session_path) + end + end end - test "user with weak level mfa gets redirected back to verify session pages after setting up mfa" do - redirect_test_mfa_weak_level(verify_session_path) + context "updating mfa level" do + should "user with otp can change mfa level" do + sign_in + @user.enable_totp!(@seed, :ui_and_gem_signin) + + visit edit_settings_path + + assert page.has_content?("UI and gem signin"), "UI and gem signin was not the default level" + + change_auth_level "UI and API (Recommended)" + fill_in "otp", with: @totp.now + click_button "Authenticate" + + assert_current_path(edit_settings_path) + assert page.has_content?("UI and API (Recommended)"), "MFA level was not updated" + end + + should "user with webauthn can change mfa level" do + fullscreen_headless_chrome_driver + + sign_in + visit edit_settings_path + + @authenticator = create_webauthn_credential_while_signed_in + + assert page.has_content?("UI and gem signin"), "UI and gem signin was not the default level" + + change_auth_level "UI and API (Recommended)" + + assert page.has_content? "Multi-factor authentication" + assert page.has_content? "Security Device" + click_on "Authenticate with security device" + + assert_current_path(edit_settings_path) + assert page.has_content?("UI and API (Recommended)"), "MFA level was not updated" + end end def redirect_test_mfa_disabled(path) @@ -128,10 +171,7 @@ def redirect_test_mfa_disabled(path) assert(page.has_content?("you are required to set up multi-factor authentication")) assert_current_path(edit_settings_path) - click_button "Register a new device" - totp = ROTP::TOTP.new(otp_key) - fill_in "otp", with: totp.now - click_button "Enable" + register_otp_device assert page.has_content? "Recovery codes" click_link "[ copy ]" @@ -171,6 +211,16 @@ def otp_key page.find_by_id("otp-key").text.match(key_regex)[0].delete("\s") end + def register_otp_device + visit edit_settings_path + click_button "Register a new device" + @otp_key = otp_key + totp = ROTP::TOTP.new(@otp_key) + fill_in "otp", with: totp.now + click_button "Enable" + @otp_key + end + def verify_password return unless page.has_css? "#verify_password_password" diff --git a/test/test_helper.rb b/test/test_helper.rb index d424e235f6c..3b9818b0274 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -6,6 +6,10 @@ if ENV["CI"] require "simplecov-cobertura" formatter SimpleCov::Formatter::CoberturaFormatter + + # Avo tests are super fragile :'( + require "minitest/retry" + Minitest::Retry.use! end end @@ -29,10 +33,6 @@ require "helpers/oauth_helpers" require "webmock/minitest" require "phlex/testing/rails/view_helper" -require "minitest/retry" - -# Avo tests are super fragile :'( -Minitest::Retry.use! # setup license early since some tests are testing Avo outside of requests # and license is set with first request @@ -155,6 +155,16 @@ def create_webauthn_credential fill_in "Email or Username", with: @user.reload.email fill_in "Password", with: @user.password click_button "Sign in" + + @authenticator = create_webauthn_credential_while_signed_in + + find(:css, ".header__popup-link").click + click_on "Sign out" + + @authenticator + end + + def create_webauthn_credential_while_signed_in visit edit_settings_path options = ::Selenium::WebDriver::VirtualAuthenticatorOptions.new( @@ -173,11 +183,9 @@ def create_webauthn_credential check "ack" click_on "Continue" + visit edit_settings_path find("div", text: credential_nickname, match: :first) - find(:css, ".header__popup-link").click - click_on "Sign out" - @user.reload @authenticator end