From 79761583660fa40ae87861e92443f3bc03d2465d Mon Sep 17 00:00:00 2001 From: Samuel Giddins Date: Tue, 9 Jul 2024 10:36:11 -0700 Subject: [PATCH 001/381] 400 when to param is an array (#4870) Fixes https://app.honeybadger.io/projects/40972/faults/109225185 --- .../api/v1/timeframe_versions_controller.rb | 2 +- .../api/v1/timeframe_versions_controller_test.rb | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/v1/timeframe_versions_controller.rb b/app/controllers/api/v1/timeframe_versions_controller.rb index 0259eb85712..31007ea9a31 100644 --- a/app/controllers/api/v1/timeframe_versions_controller.rb +++ b/app/controllers/api/v1/timeframe_versions_controller.rb @@ -31,7 +31,7 @@ def from_time def to_time @to_time ||= params[:to].blank? ? Time.zone.now : Time.iso8601(params[:to]) - rescue ArgumentError + rescue ArgumentError, TypeError raise InvalidTimeframeParameterError, 'the "to" parameter must be iso8601 formatted' end diff --git a/test/functional/api/v1/timeframe_versions_controller_test.rb b/test/functional/api/v1/timeframe_versions_controller_test.rb index b5953d74fdd..44f1d968546 100644 --- a/test/functional/api/v1/timeframe_versions_controller_test.rb +++ b/test/functional/api/v1/timeframe_versions_controller_test.rb @@ -52,6 +52,16 @@ class Api::V1::TimeframeVersionsControllerTest < ActionController::TestCase assert_includes response.body, "iso8601" end + should 'return a bad request with message when "to" is not primitive' do + get :index, format: :json, params: { + from: Time.zone.parse("2017-11-09").iso8601, + to: ["2017-11-12"] + } + + assert_equal 400, response.status + assert_includes response.body, "iso8601" + end + should 'return a bad request with message when "from" is invalid' do get :index, format: :json, params: { from: "2017-11-09", From fe420fee405a58a024e60ab7d488a2dea2a7f942 Mon Sep 17 00:00:00 2001 From: Andre Arko Date: Tue, 9 Jul 2024 20:24:12 -0700 Subject: [PATCH 002/381] Make it possible to run migrations again Funny story, strong_migrations was [upgraded to 2.0.0 last week](https://github.com/rubygems/rubygems.org/commit/7505e0507496c60b2b1d22ee8a6d57422b58b069). It turns out that version 2.0.0 dropped support for Postgres 11, and requires a minimum of Postgres 12. Funnier story, we have hardcoded the strong_migrations initializer to always act as if we are running on Postgres 11.3, which means that all migrations error out: ``` bin/rails aborted! (1.7ms) SELECT pg_advisory_unlock(4040961485751852690) StandardError: An error has occurred, this and all later migrations canceled: (StandardError) PostgreSQL version (11.3) not supported in this version of Strong Migrations (2.0.0) ``` That error shows up regardless of the version of postgres you are actually using, and made me tear my hair out for about half an hour trying to figure out how Rails was talking to postgres 11 when I didn't even have it installed on my computer anymore. Anyway, I have verified that production postgres has been upgraded to 13, and that is why I have changed the strong_migrations initializer to reflect that we want to check migrations as if we are using postgres 13, even if local development is happening against a different version. In the future, we may want to add updating this file to our database upgrade runbook! --- config/initializers/strong_migrations.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/initializers/strong_migrations.rb b/config/initializers/strong_migrations.rb index 17f3f042095..1d977dad858 100644 --- a/config/initializers/strong_migrations.rb +++ b/config/initializers/strong_migrations.rb @@ -12,7 +12,7 @@ # Set the version of the production database # so the right checks are run in development -StrongMigrations.target_version = "11.3" +StrongMigrations.target_version = "13" # Add custom checks # StrongMigrations.add_check do |method, args| From 13dc50c27f18fb4bd5c0ff8021f2157beb3b9552 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Jul 2024 04:34:06 +0000 Subject: [PATCH 003/381] Bump actions/upload-artifact from 4.3.3 to 4.3.4 (#4865) --- .github/workflows/lint.yml | 2 +- .github/workflows/test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index e27fe434e21..ff0a4db2628 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -60,7 +60,7 @@ jobs: env: ENVIRONMENT: "${{ matrix.environment }}" REVISION: "${{ github.sha }}" - - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 with: name: "${{ matrix.environment }}.rendered.yaml" path: "config/deploy/${{ matrix.environment }}.rendered.yaml" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bcdfd2a0249..b07f90d106b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -56,7 +56,7 @@ jobs: - name: Save capybara screenshots if: ${{ failure() && steps.test-all.outcome == 'failure' }} - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 with: name: capybara-screenshots-${{ matrix.tests.name }}-${{ matrix.rubygems.name }} path: tmp/capybara From 890a43b80bc38faff00b8e4e61f1134f9b190f50 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Jul 2024 04:34:39 +0000 Subject: [PATCH 004/381] Bump ruby/setup-ruby from 1.184.0 to 1.185.0 (#4866) --- .github/workflows/lint.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index ff0a4db2628..a4f172a69ef 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@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # v1.184.0 + - uses: ruby/setup-ruby@3a77c29278ae80936b4cb030fefc7d21c96c786f # v1.185.0 with: bundler-cache: true - name: Rubocop @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # v1.184.0 + - uses: ruby/setup-ruby@3a77c29278ae80936b4cb030fefc7d21c96c786f # v1.185.0 with: bundler-cache: true - name: Brakeman @@ -33,7 +33,7 @@ jobs: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # v1.184.0 + - uses: ruby/setup-ruby@3a77c29278ae80936b4cb030fefc7d21c96c786f # v1.185.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@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # v1.184.0 + - uses: ruby/setup-ruby@3a77c29278ae80936b4cb030fefc7d21c96c786f # v1.185.0 with: bundler-cache: true - name: krane render From 3a4b7a7907ce6a4f93c5485ffe2dac81dbbe340a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Jul 2024 04:34:51 +0000 Subject: [PATCH 005/381] Bump rails_semantic_logger from 4.16.0 to 4.17.0 (#4868) --- Gemfile | 2 +- Gemfile.lock | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Gemfile b/Gemfile index 5cc75dda44b..40f71813659 100644 --- a/Gemfile +++ b/Gemfile @@ -68,7 +68,7 @@ gem "groupdate", "~> 6.2" # Logging gem "amazing_print", "~> 1.6" -gem "rails_semantic_logger", "~> 4.16" +gem "rails_semantic_logger", "~> 4.17" gem "pp", "0.5.0" # Former default gems diff --git a/Gemfile.lock b/Gemfile.lock index 18526310b42..355fb00f4cb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -305,7 +305,7 @@ GEM activesupport (>= 3.0) nokogiri (>= 1.6) io-console (0.7.2) - irb (1.13.2) + irb (1.14.0) rdoc (>= 4.0.0) reline (>= 0.4.2) jmespath (1.6.2) @@ -565,10 +565,10 @@ GEM rails-i18n (7.0.9) i18n (>= 0.7, < 2) railties (>= 6.0.0, < 8) - rails_semantic_logger (4.16.0) + rails_semantic_logger (4.17.0) rack railties (>= 5.1) - semantic_logger (~> 4.13) + semantic_logger (~> 4.16) railties (7.1.3.4) actionpack (= 7.1.3.4) activesupport (= 7.1.3.4) @@ -662,7 +662,7 @@ GEM rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) semantic (1.6.1) - semantic_logger (4.15.0) + semantic_logger (4.16.0) concurrent-ruby (~> 1.0) shoryuken (6.2.1) aws-sdk-core (>= 2) @@ -851,7 +851,7 @@ DEPENDENCIES rails-controller-testing (~> 1.0) rails-erd (~> 1.7) rails-i18n (~> 7.0) - rails_semantic_logger (~> 4.16) + rails_semantic_logger (~> 4.17) rbtrace (~> 0.5.1) rdoc (~> 6.7) roadie-rails (~> 3.2) @@ -999,7 +999,7 @@ CHECKSUMS importmap-rails (2.0.1) sha256=e739a6e70c09f797688c6983fa79567ec1edc9becc30d55b3f7cc897b1825586 inline_svg (1.9.0) sha256=f44c5e3d2e401fd619ad3047b7c8cee384517d855edb1d1fb1a248d3cae535d6 io-console (0.7.2) sha256=f0dccff252f877a4f60d04a4dc6b442b185ebffb4b320ab69212a92b48a7a221 - irb (1.13.2) sha256=e72928d8047a515cd868967ecafbe5388097402449fb8ef658c33db6ccde8117 + irb (1.14.0) sha256=53d805013bbd194874b8c13a56aca6aebcd11dd79166d88724f8a434fedde615 jmespath (1.6.2) sha256=238d774a58723d6c090494c8879b5e9918c19485f7e840f2c1c7532cf84ebcb1 job-iteration (1.5.1) sha256=1428ad5b308adbaae8776c16b7792a846eb1ad7f4ab3c6e0f9668dd2ab1179e5 json (2.7.2) sha256=1898b5cbc81cd36c0fd4d0b7ad2682c39fb07c5ff682fc6265f678f550d4982c @@ -1094,7 +1094,7 @@ CHECKSUMS rails-erd (1.7.2) sha256=0b17d0fba25d319d8da8af7a3e5e2149d02d6187cc7351e8be43423f07c48bcd rails-html-sanitizer (1.6.0) sha256=86e9f19d2e6748890dcc2633c8945ca45baa08a1df9d8c215ce17b3b0afaa4de rails-i18n (7.0.9) sha256=c184db80a7c7bf21c14e0e400fe9e27c4c20312f019aaff5b364a82858dc1369 - rails_semantic_logger (4.16.0) sha256=766f6cd482f3c811083b24777ea8ac04bb7f44c4fdb189cf1af3ae2b9b844cf6 + rails_semantic_logger (4.17.0) sha256=cc10cca01491736596cd5ab40b52b3bbf98338d9d1f5a7916b2be10231615047 railties (7.1.3.4) sha256=6c6049f3a788669d94f95c7bf6378204ae94098567cc25237e3c73dac4a21afc rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a rake (13.2.1) sha256=46cb38dae65d7d74b6020a4ac9d48afed8eb8149c040eccf0523bec91907059d @@ -1132,7 +1132,7 @@ CHECKSUMS searchkick (5.3.1) sha256=dc1181543f6a68354e380651f235fa7f3df6a09e4cd67fc284dc293fa9860f57 selenium-webdriver (4.22.0) sha256=644370abcdcf1f14b2581c125d39014a1933b20e355c74b0dc5d0ca877a45d66 semantic (1.6.1) sha256=3cdbb48f59198ebb782a3fdfb87b559e0822a311610db153bae22777a7d0c163 - semantic_logger (4.15.0) sha256=ec4f56122b5d2e2117d148b86c69fb62c1194a2b01a271be04ba8678a85f81ff + semantic_logger (4.16.0) sha256=ffba0bd0e008ceaf6be26da588f610a61208b9a9f55676b32729e962904023d9 shoryuken (6.2.1) sha256=95ddc0a717624a54e799d25a0a05100cb5a0c3728a96211935c214faaf16b3b6 shoulda-context (3.0.0.rc1) sha256=6e0d9d52ab798c13bc2b490c8537d4bf30cfd318a1ea839c39a66d1d293c6a1a shoulda-matchers (6.2.0) sha256=a702c059c5f3bbda2295827231a28654e33063d7c4d409662980ec630207d8dd From c00b5657a871d0dffff65efba54286690d2510b9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Jul 2024 04:35:08 +0000 Subject: [PATCH 006/381] Bump faraday from 2.9.2 to 2.10.0 (#4869) --- Gemfile | 2 +- Gemfile.lock | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index 40f71813659..fda750a185f 100644 --- a/Gemfile +++ b/Gemfile @@ -13,7 +13,7 @@ gem "dalli", "~> 3.2" gem "datadog", "~> 2.1", require: "datadog/auto_instrument" gem "dogstatsd-ruby", "~> 5.5" gem "google-protobuf", "~> 4.27" -gem "faraday", "~> 2.9" +gem "faraday", "~> 2.10" gem "faraday-retry", "~> 2.2" gem "good_job", "~> 3.29" gem "gravtastic", "~> 3.2" diff --git a/Gemfile.lock b/Gemfile.lock index 355fb00f4cb..817922894bb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -239,8 +239,9 @@ GEM factory_bot_rails (6.4.3) factory_bot (~> 6.4) railties (>= 5.0.0) - faraday (2.9.2) + faraday (2.10.0) faraday-net_http (>= 2.0, < 3.2) + logger faraday-follow_redirects (0.3.0) faraday (>= 1, < 3) faraday-net_http (3.1.0) @@ -801,7 +802,7 @@ DEPENDENCIES dogstatsd-ruby (~> 5.5) dotenv-rails (~> 3.1) factory_bot_rails (~> 6.4) - faraday (~> 2.9) + faraday (~> 2.10) faraday-retry (~> 2.2) faraday_middleware-aws-sigv4 (~> 1.0) good_job (~> 3.29) @@ -970,7 +971,7 @@ CHECKSUMS execjs (2.9.1) sha256=e8fd066f6df60c8e8fbebc32c6fb356b5212c77374e8416a9019ca4bb154dcfb factory_bot (6.4.5) sha256=d71dd29bc95f0ec2bf27e3dd9b1b4d557bd534caca744663cb7db4bacf3198be factory_bot_rails (6.4.3) sha256=ea73ceac1c0ff3dc11fff390bf2ea8a2604066525ed8ecd3b3bc2c267226dcc8 - faraday (2.9.2) sha256=6595edbe3b4663223e52a315f6bf2bca97ea1527bab7e02a926bf8afcf7423a4 + faraday (2.10.0) sha256=1a3e6c02acc511fc334d799521f1013e449bde38aa2dceb3af71e8030519bda9 faraday-follow_redirects (0.3.0) sha256=d92d975635e2c7fe525dd494fcd4b9bb7f0a4a0ec0d5f4c15c729530fdb807f9 faraday-net_http (3.1.0) sha256=1627be414960d0131691190ff524506ba6607402a50fb6eccda9e64ca60f859f faraday-retry (2.2.1) sha256=4146fed14549c0580bf14591fca419a40717de0dd24f267a8ec2d9a728677608 From 1c799b214a0c493624066eb50dc1b6f342b22f4c Mon Sep 17 00:00:00 2001 From: Colby Swandale <996377+colby-swandale@users.noreply.github.com> Date: Wed, 10 Jul 2024 16:10:52 +1000 Subject: [PATCH 007/381] Update all Github Actions workflows to `ubuntu-24.04` (#4873) * Update all Github Actions to 'ubuntu-24.04' * docker-copose -> docker compose --- .github/workflows/codeql.yml | 2 +- .github/workflows/docker.yml | 4 ++-- .github/workflows/lint.yml | 8 ++++---- .github/workflows/scorecards.yml | 2 +- .github/workflows/test.yml | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 361185db215..49a79c89f3e 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -26,7 +26,7 @@ permissions: # added using https://github.com/step-security/secure-workflows jobs: analyze: name: Analyze - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 permissions: actions: read contents: read diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 7ddff773819..9ecd1b5dd62 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -12,7 +12,7 @@ permissions: jobs: build: name: Docker build (and optional push) - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 env: RUBYGEMS_VERSION: 3.5.14 RUBY_VERSION: 3.3.3 @@ -29,7 +29,7 @@ jobs: restore-keys: | ${{ runner.os }}-rubygems-org - name: Install and start services (needed for image test) - run: docker-compose up -d + run: docker compose up -d - name: Configure AWS credentials from Production account uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 if: github.secret_source != 'None' diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index a4f172a69ef..09cb893e20e 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -10,7 +10,7 @@ permissions: jobs: rubocop: name: Rubocop - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: ruby/setup-ruby@3a77c29278ae80936b4cb030fefc7d21c96c786f # v1.185.0 @@ -20,7 +20,7 @@ jobs: run: bundle exec rubocop brakeman: name: Brakeman - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: ruby/setup-ruby@3a77c29278ae80936b4cb030fefc7d21c96c786f # v1.185.0 @@ -30,7 +30,7 @@ jobs: run: bundle exec brakeman importmap: name: Importmap Verify - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: ruby/setup-ruby@3a77c29278ae80936b4cb030fefc7d21c96c786f # v1.185.0 @@ -40,7 +40,7 @@ jobs: run: bundle exec rake importmap:verify kubeconform: name: Kubeconform - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: matrix: kubernetes_version: ["1.29.1"] diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 6c7bd34107c..10dd6c427b4 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -20,7 +20,7 @@ permissions: read-all jobs: analysis: name: Scorecards analysis - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 permissions: # Needed to upload the results to code-scanning dashboard. security-events: write diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b07f90d106b..e132e78f586 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,7 @@ jobs: status_check: name: All required tests passing check needs: [rails] - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 if: always() steps: - run: /bin/${{ (needs.rails.result == 'success' || needs.rails.result == 'skipped') }} From 5f7cf6195d2f41416e913a8dca64e02a2c460653 Mon Sep 17 00:00:00 2001 From: Colby Swandale <996377+colby-swandale@users.noreply.github.com> Date: Wed, 10 Jul 2024 20:32:25 +1000 Subject: [PATCH 008/381] Set OpenSearch docker image java options (#4874) --- docker-compose.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 3bcc4b47463..db1c99600d7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -20,6 +20,7 @@ services: environment: - discovery.type=single-node - DISABLE_SECURITY_PLUGIN=true + - "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m" ports: - "9200:9200" healthcheck: @@ -41,6 +42,7 @@ services: environment: - 'OPENSEARCH_HOSTS=["http://search:9200"]' - "DISABLE_SECURITY_DASHBOARDS_PLUGIN=true" + - "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m" healthcheck: test: [ From 62b2cbbb35161d9cdf7fa376c0eb154f0ab5d5fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Jul 2024 23:18:07 -0700 Subject: [PATCH 009/381] Bump ruby/setup-ruby from 1.185.0 to 1.186.0 (#4875) --- .github/workflows/lint.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 09cb893e20e..f76a4ab64c6 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: ruby/setup-ruby@3a77c29278ae80936b4cb030fefc7d21c96c786f # v1.185.0 + - uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # v1.186.0 with: bundler-cache: true - name: Rubocop @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: ruby/setup-ruby@3a77c29278ae80936b4cb030fefc7d21c96c786f # v1.185.0 + - uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # v1.186.0 with: bundler-cache: true - name: Brakeman @@ -33,7 +33,7 @@ jobs: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: ruby/setup-ruby@3a77c29278ae80936b4cb030fefc7d21c96c786f # v1.185.0 + - uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # v1.186.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@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: ruby/setup-ruby@3a77c29278ae80936b4cb030fefc7d21c96c786f # v1.185.0 + - uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # v1.186.0 with: bundler-cache: true - name: krane render From 9309f276ee02e0a242422ddeca887d2916bfc2c9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jul 2024 16:08:49 +0000 Subject: [PATCH 010/381] Bump ruby/setup-ruby from 1.186.0 to 1.187.0 (#4882) --- .github/workflows/lint.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index f76a4ab64c6..0f8daf2864a 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # v1.186.0 + - uses: ruby/setup-ruby@161cd54b698f1fb3ea539faab2e036d409550e3c # v1.187.0 with: bundler-cache: true - name: Rubocop @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # v1.186.0 + - uses: ruby/setup-ruby@161cd54b698f1fb3ea539faab2e036d409550e3c # v1.187.0 with: bundler-cache: true - name: Brakeman @@ -33,7 +33,7 @@ jobs: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # v1.186.0 + - uses: ruby/setup-ruby@161cd54b698f1fb3ea539faab2e036d409550e3c # v1.187.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@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # v1.186.0 + - uses: ruby/setup-ruby@161cd54b698f1fb3ea539faab2e036d409550e3c # v1.187.0 with: bundler-cache: true - name: krane render From 328c3c30ee679a9fe650c2ce65647ab57572c2c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jul 2024 16:09:06 +0000 Subject: [PATCH 011/381] Bump datadog from 2.1.0 to 2.2.0 (#4879) --- Gemfile | 2 +- Gemfile.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Gemfile b/Gemfile index fda750a185f..0efe13d71b8 100644 --- a/Gemfile +++ b/Gemfile @@ -10,7 +10,7 @@ gem "aws-sdk-sqs", "~> 1.80" gem "bootsnap", "~> 1.18" gem "clearance", "~> 2.7" gem "dalli", "~> 3.2" -gem "datadog", "~> 2.1", require: "datadog/auto_instrument" +gem "datadog", "~> 2.2", require: "datadog/auto_instrument" gem "dogstatsd-ruby", "~> 5.5" gem "google-protobuf", "~> 4.27" gem "faraday", "~> 2.10" diff --git a/Gemfile.lock b/Gemfile.lock index 817922894bb..9e4ebc9974f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -194,9 +194,9 @@ GEM sprockets (> 3.0) sprockets-rails tilt - datadog (2.1.0) + datadog (2.2.0) debase-ruby_core_source (= 3.3.1) - libdatadog (~> 9.0.0.1.0) + libdatadog (~> 10.0.0.1.0) libddwaf (~> 1.14.0.0.0) msgpack datadog-ci (1.1.0) @@ -354,7 +354,7 @@ GEM letter_opener (~> 1.9) railties (>= 6.1) rexml - libdatadog (9.0.0.1.0) + libdatadog (10.0.0.1.0) libddwaf (1.14.0.0.0) ffi (~> 1.0) listen (3.9.0) @@ -795,7 +795,7 @@ DEPENDENCIES csv (~> 3.3) dalli (~> 3.2) dartsass-sprockets (~> 3.1) - datadog (~> 2.1) + datadog (~> 2.2) datadog-ci (~> 1.1) derailed_benchmarks (~> 2.1) discard (~> 1.3) @@ -951,7 +951,7 @@ CHECKSUMS csv (3.3.0) sha256=0bbd1defdc31134abefed027a639b3723c2753862150f4c3ee61cab71b20d67d dalli (3.2.8) sha256=2e63595084d91fae2655514a02c5d4fc0f16c0799893794abe23bf628bebaaa5 dartsass-sprockets (3.1.0) sha256=c238ec9f7f496489ac5a7813cd1f83d1e077a1826921acefc7e290a521b7a20a - datadog (2.1.0) sha256=6a9be58bb3dc01e1890d1b3452cef262de925bda9ad0bfdb8bb854f5f9384e0b + datadog (2.2.0) sha256=fa96d565e055593294706d7767c4d3213b5250f0ddd2b8697b868ae60dbdda4a datadog-ci (1.1.0) sha256=15153b9f15deb5e55e81c91aaff6911c8dc7f4e2f139f80e803d079890739fbd date (3.3.4) sha256=971f2cb66b945bcbea4ddd9c7908c9400b31a71bc316833cb42fa584b59d3291 dead_end (4.0.0) sha256=695c8438993bb4c5415b1618a1b6e0afcae849ef2812fb8cb3846723904307eb @@ -1016,7 +1016,7 @@ CHECKSUMS ld-eventsource (2.2.2) sha256=5ea087a6f06bbd8e325d2c1aaead50f37f13d025b952985739e9380a78a96beb letter_opener (1.10.0) sha256=2ff33f2e3b5c3c26d1959be54b395c086ca6d44826e8bf41a14ff96fdf1bdbb2 letter_opener_web (3.0.0) sha256=3f391efe0e8b9b24becfab5537dfb17a5cf5eb532038f947daab58cb4b749860 - libdatadog (9.0.0.1.0) sha256=2a24dd3ee462e59de04f098687ed3d98823042aebfdd3f1b75fd92374b926f07 + libdatadog (10.0.0.1.0) sha256=2e2c2000f1250cd3bb3721bdd0672dcdb584e60eee13d4a4089fbce1cf40dafc libddwaf (1.14.0.0.0) sha256=b91ea9675f7d79d1cd10dd6513e3706760ac442cb8902164fbcef79b7082a8fd listen (3.9.0) sha256=db9e4424e0e5834480385197c139cb6b0ae0ef28cc13310cfd1ca78377d59c67 llhttp-ffi (0.5.0) sha256=496f40ad44bcbf99de02da1f26b1ad64e6593cd487b931508a86228e2a3af0fa From 51a79ceba9c67c2df3a21a1d0ff1618fa510a26f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jul 2024 16:09:25 +0000 Subject: [PATCH 012/381] Bump pghero from 3.5.0 to 3.6.0 (#4878) --- Gemfile | 2 +- Gemfile.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Gemfile b/Gemfile index 0efe13d71b8..1d1c2d0beaa 100644 --- a/Gemfile +++ b/Gemfile @@ -56,7 +56,7 @@ gem "strong_migrations", "~> 2.0" gem "phlex-rails", "~> 1.2" gem "discard", "~> 1.3" gem "user_agent_parser", "~> 2.18" -gem "pghero", "~> 3.5" +gem "pghero", "~> 3.6" gem "timescaledb", "~> 0.2" # Admin dashboard diff --git a/Gemfile.lock b/Gemfile.lock index 9e4ebc9974f..87bb84d09bc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -485,8 +485,8 @@ GEM pg (1.5.6) pg_query (5.1.0) google-protobuf (>= 3.22.3) - pghero (3.5.0) - activerecord (>= 6) + pghero (3.6.0) + activerecord (>= 6.1) phlex (1.10.2) phlex-rails (1.2.1) phlex (~> 1.10.0) @@ -836,7 +836,7 @@ DEPENDENCIES opensearch-ruby (~> 3.3) pg (~> 1.5) pg_query (~> 5.1) - pghero (~> 3.5) + pghero (~> 3.6) phlex-rails (~> 1.2) pp (= 0.5.0) prosopite (~> 1.4) @@ -1066,7 +1066,7 @@ CHECKSUMS parser (3.3.3.0) sha256=a2e23c90918d9b7e866b18dca2b6835f227769dd2fa8e59c5841f3389cf53eeb pg (1.5.6) sha256=4bc3ad2438825eea68457373555e3fd4ea1a82027b8a6be98ef57c0d57292b1c pg_query (5.1.0) sha256=b7f7f47c864f08ccbed46a8244906fb6ee77ee344fd27250717963928c93145d - pghero (3.5.0) sha256=7b459d383673e358017d0dd210c11b6a82bbfb340c73236ba0e50bb6c0351e6a + pghero (3.6.0) sha256=cad9cb865f99ff40bb5ba47d3dae20d06be06ac8ea6b01172f6a8ccc85671109 phlex (1.10.2) sha256=49dca7df081258f937be5e4ee0a81b11743f2b4fea25ac7537912b9c9344b1e6 phlex-rails (1.2.1) sha256=1d80709c02114cda869951d22bfca189b5f208d1eb89f2e6fafbe3c0240a822f pp (0.5.0) sha256=f8f40bc2ba9e1ab351b9458151da3a89f46034f7f599a8e0a06abb9b9f4411dd From e311c7e163fbf6021bd1bf9bdb2bb4af88e54a25 Mon Sep 17 00:00:00 2001 From: Martin Emde Date: Thu, 11 Jul 2024 15:55:53 -0700 Subject: [PATCH 013/381] I18n localize mfa error strings in API (#4876) --- app/controllers/api/base_controller.rb | 65 ++++------------- app/controllers/api/v1/api_keys_controller.rb | 11 +-- .../api/v1/deletions_controller.rb | 5 +- app/controllers/api/v1/owners_controller.rb | 6 +- app/controllers/api/v1/rubygems_controller.rb | 4 +- .../api/v1/web_hooks_controller.rb | 2 +- app/models/user/with_private_fields.rb | 7 +- config/locales/de.yml | 9 +++ config/locales/en.yml | 19 +++++ config/locales/es.yml | 12 +++- config/locales/fr.yml | 9 +++ config/locales/ja.yml | 9 +++ config/locales/nl.yml | 9 +++ config/locales/pt-BR.yml | 9 +++ config/locales/zh-CN.yml | 9 +++ config/locales/zh-TW.yml | 9 +++ .../api/v1/api_keys_controller_test.rb | 14 +--- .../api/v1/deletions_controller_test.rb | 39 +++-------- .../api/v1/owners_controller_test.rb | 70 +++++-------------- .../api/v1/profiles_controller_test.rb | 32 +++------ .../api/v1/rubygems_controller_test.rb | 53 ++++---------- test/models/user/with_private_fields_test.rb | 23 +++--- 22 files changed, 180 insertions(+), 245 deletions(-) diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb index 46b886f3ae9..5650be62848 100644 --- a/app/controllers/api/base_controller.rb +++ b/app/controllers/api/base_controller.rb @@ -2,7 +2,7 @@ class Api::BaseController < ApplicationController skip_before_action :verify_authenticity_token after_action :skip_session - rescue_from(Pundit::NotAuthorizedError) { |_| render_api_key_forbidden } + rescue_from(Pundit::NotAuthorizedError) { |_| render_forbidden(t(:api_key_forbidden)) } private @@ -17,13 +17,13 @@ def gem_name def find_rubygem_by_name @rubygem = Rubygem.find_by name: gem_name return if @rubygem - render plain: "This gem could not be found", status: :not_found + render plain: t(:api_gem_not_found), status: :not_found end def verify_api_key_gem_scope return unless @api_key.rubygem && @api_key.rubygem != @rubygem - render plain: "This API key cannot perform the specified action on this gem.", status: :forbidden + render_forbidden t(:api_key_insufficient_scope) end def verify_with_otp @@ -35,54 +35,22 @@ def verify_with_otp def verify_mfa_requirement if @rubygem && !@rubygem.mfa_requirement_satisfied_for?(@api_key.user) - render plain: "Gem requires MFA enabled; You do not have MFA enabled yet.", status: :forbidden + render_forbidden t("multifactor_auths.api.mfa_required") elsif @api_key.mfa_required_not_yet_enabled? - render_mfa_setup_required_error + render_forbidden t("multifactor_auths.api.mfa_required_not_yet_enabled").chomp elsif @api_key.mfa_required_weak_level_enabled? - render_mfa_strong_level_required_error + render_forbidden t("multifactor_auths.api.mfa_required_weak_level_enabled").chomp end end - def response_with_mfa_warning(response) - message = response + def response_with_mfa_warning(message) if @api_key.mfa_recommended_not_yet_enabled? - message += <<~WARN.chomp - - - [WARNING] For protection of your account and gems, we encourage you to set up multi-factor authentication \ - at https://rubygems.org/totp/new. Your account will be required to have MFA enabled in the future. - WARN + +message << "\n\n" << t("multifactor_auths.api.mfa_recommended_not_yet_enabled").chomp elsif @api_key.mfa_recommended_weak_level_enabled? - message += <<~WARN.chomp - - - [WARNING] For protection of your account and gems, we encourage you to change your multi-factor authentication \ - level to 'UI and gem signin' or 'UI and API' at https://rubygems.org/settings/edit. \ - Your account will be required to have MFA enabled on one of these levels in the future. - WARN + +message << "\n\n" << t("multifactor_auths.api.mfa_recommended_weak_level_enabled").chomp + else + message end - - message - end - - def render_mfa_setup_required_error - error = <<~ERROR.chomp - [ERROR] For protection of your account and your gems, you are required to set up multi-factor authentication \ - at https://rubygems.org/totp/new. - - Please read our blog post for more details (https://blog.rubygems.org/2022/08/15/requiring-mfa-on-popular-gems.html). - ERROR - render_forbidden(error) - end - - def render_mfa_strong_level_required_error - error = <<~ERROR.chomp - [ERROR] For protection of your account and your gems, you are required to change your MFA level to 'UI and gem signin' or 'UI and API' \ - at https://rubygems.org/settings/edit. - - Please read our blog post for more details (https://blog.rubygems.org/2022/08/15/requiring-mfa-on-popular-gems.html). - ERROR - render_forbidden(error) end def authenticate_with_api_key @@ -92,7 +60,7 @@ def authenticate_with_api_key return render_unauthorized unless @api_key set_tags "gemcutter.api_key.owner" => @api_key.owner.to_gid, "gemcutter.user.api_key_id" => @api_key.id Current.user = @api_key.user - render_soft_deleted_api_key if @api_key.soft_deleted? + render_forbidden(t(:api_key_soft_deleted)) if @api_key.soft_deleted? end def pundit_user @@ -108,15 +76,14 @@ def authorize(record, query = nil) end def verify_user_api_key - render_api_key_forbidden if @api_key.user.blank? + render_forbidden(t(:api_key_forbidden)) if @api_key.user.blank? end def render_unauthorized render plain: t(:please_sign_up), status: :unauthorized end - def render_api_key_forbidden(error = nil) - error = error&.message || t(:api_key_forbidden) + def render_forbidden(error = t(:api_key_forbidden)) respond_to do |format| format.any(:all) { render plain: error, status: :forbidden } format.json { render json: { error: }, status: :forbidden } @@ -124,10 +91,6 @@ def render_api_key_forbidden(error = nil) end end - def render_soft_deleted_api_key - render plain: "An invalid API key cannot be used. Please delete it and create a new one.", status: :forbidden - end - def skip_session request.session_options[:skip] = true end diff --git a/app/controllers/api/v1/api_keys_controller.rb b/app/controllers/api/v1/api_keys_controller.rb index a4c7d53b30d..a89511f998f 100644 --- a/app/controllers/api/v1/api_keys_controller.rb +++ b/app/controllers/api/v1/api_keys_controller.rb @@ -49,10 +49,13 @@ def update def check_mfa(user) if user&.mfa_gem_signin_authorized?(otp) - return render_mfa_setup_required_error if user.mfa_required_not_yet_enabled? - return render_mfa_strong_level_required_error if user.mfa_required_weak_level_enabled? - - yield + if user.mfa_required_not_yet_enabled? + render_forbidden t("multifactor_auths.api.mfa_required_not_yet_enabled").chomp + elsif user.mfa_required_weak_level_enabled? + render_forbidden t("multifactor_auths.api.mfa_required_weak_level_enabled").chomp + else + yield + end elsif user&.mfa_enabled? prompt_text = otp.present? ? t(:otp_incorrect) : t(:otp_missing) render plain: prompt_text, status: :unauthorized diff --git a/app/controllers/api/v1/deletions_controller.rb b/app/controllers/api/v1/deletions_controller.rb index 3dea90ad1ed..4ead8e71c2e 100644 --- a/app/controllers/api/v1/deletions_controller.rb +++ b/app/controllers/api/v1/deletions_controller.rb @@ -5,7 +5,7 @@ class Api::V1::DeletionsController < Api::BaseController before_action :verify_api_key_gem_scope before_action :validate_gem_and_version before_action :verify_with_otp - before_action :render_api_key_forbidden, if: :api_key_unauthorized? + before_action :render_forbidden, if: :api_key_unauthorized? before_action :verify_mfa_requirement def create @@ -34,8 +34,7 @@ def validate_gem_and_version render plain: response_with_mfa_warning(t(:this_rubygem_could_not_be_found)), status: :not_found elsif !@rubygem.owned_by?(@api_key.user) - render plain: response_with_mfa_warning("You do not have permission to delete this gem."), - status: :forbidden + render_forbidden response_with_mfa_warning("You do not have permission to delete this gem.") else begin version = params.permit(:version).require(:version) diff --git a/app/controllers/api/v1/owners_controller.rb b/app/controllers/api/v1/owners_controller.rb index d9f00ea7a64..b6203b73be0 100644 --- a/app/controllers/api/v1/owners_controller.rb +++ b/app/controllers/api/v1/owners_controller.rb @@ -15,7 +15,7 @@ def show end def create - return render_api_key_forbidden unless @api_key.can_add_owner? + return render_forbidden(t(:api_key_forbidden)) unless @api_key.can_add_owner? owner = User.find_by_name(email_param) if owner @@ -34,7 +34,7 @@ def create end def destroy - return render_api_key_forbidden unless @api_key.can_remove_owner? + return render_forbidden(t(:api_key_forbidden)) unless @api_key.can_remove_owner? owner = @rubygem.owners_including_unconfirmed.find_by_name(email_param) if owner @@ -43,7 +43,7 @@ def destroy OwnersMailer.owner_removed(ownership.user_id, @api_key.user.id, ownership.rubygem_id).deliver_later render plain: response_with_mfa_warning("Owner removed successfully.") else - render plain: response_with_mfa_warning("Unable to remove owner."), status: :forbidden + render_forbidden response_with_mfa_warning("Unable to remove owner.") end else render plain: response_with_mfa_warning("Owner could not be found."), status: :not_found diff --git a/app/controllers/api/v1/rubygems_controller.rb b/app/controllers/api/v1/rubygems_controller.rb index 4d6793e1922..54a27a71402 100644 --- a/app/controllers/api/v1/rubygems_controller.rb +++ b/app/controllers/api/v1/rubygems_controller.rb @@ -8,7 +8,7 @@ class Api::V1::RubygemsController < Api::BaseController after_action :cors_set_access_control_headers, only: :show def index - return render_forbidden unless @api_key.can_index_rubygems? + return render_forbidden(t(:api_key_insufficient_scope)) unless @api_key.can_index_rubygems? @rubygems = @api_key.user.rubygems.with_versions .preload(:linkset, :gem_download, most_recent_version: { dependencies: :rubygem, gem_download: nil }) @@ -33,7 +33,7 @@ def show end def create - return render_api_key_forbidden unless @api_key.can_push_rubygem? + return render_forbidden(t(:api_key_insufficient_scope)) unless @api_key.can_push_rubygem? gemcutter = Pusher.new(@api_key, request.body, request:) gemcutter.process diff --git a/app/controllers/api/v1/web_hooks_controller.rb b/app/controllers/api/v1/web_hooks_controller.rb index 301d73a20b5..ac5a63726c2 100644 --- a/app/controllers/api/v1/web_hooks_controller.rb +++ b/app/controllers/api/v1/web_hooks_controller.rb @@ -1,7 +1,7 @@ class Api::V1::WebHooksController < Api::BaseController before_action :authenticate_with_api_key before_action :verify_user_api_key - before_action :render_api_key_forbidden, if: :api_key_unauthorized? + before_action :render_forbidden, if: :api_key_unauthorized? before_action :find_rubygem_by_name, :set_url, except: :index def index diff --git a/app/models/user/with_private_fields.rb b/app/models/user/with_private_fields.rb index 23a9a3a6952..164836e3dd9 100644 --- a/app/models/user/with_private_fields.rb +++ b/app/models/user/with_private_fields.rb @@ -10,12 +10,9 @@ def payload def mfa_warning if mfa_recommended_not_yet_enabled? - "[WARNING] For protection of your account and gems, we encourage you to set up multi-factor authentication " \ - "at https://rubygems.org/totp/new. Your account will be required to have MFA enabled in the future." + I18n.t("multifactor_auths.api.mfa_recommended_not_yet_enabled").chomp elsif mfa_recommended_weak_level_enabled? - "[WARNING] For protection of your account and gems, we encourage you to change your multi-factor authentication " \ - "level to 'UI and gem signin' or 'UI and API' at https://rubygems.org/settings/edit. " \ - "Your account will be required to have MFA enabled on one of these levels in the future." + I18n.t("multifactor_auths.api.mfa_recommended_weak_level_enabled").chomp end end end diff --git a/config/locales/de.yml b/config/locales/de.yml index d490bee4403..5d8b96c1658 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -26,7 +26,10 @@ de: locale_name: Deutsch none: None not_found: Nicht gefunden + api_gem_not_found: api_key_forbidden: + api_key_soft_deleted: + api_key_insufficient_scope: please_sign_up: Zugriff verweigert. Bitte melden Sie sich unter https://rubygems.org mit einem Konto an please_sign_in: Bitte melden Sie sich an, um fortzufahren. @@ -511,6 +514,12 @@ de: die Sicherheit deines Kontos, indem du ein neues Gerät einrichtest. Erfahre mehr!" + api: + mfa_required: + mfa_required_not_yet_enabled: + mfa_required_weak_level_enabled: + mfa_recommended_not_yet_enabled: + mfa_recommended_weak_level_enabled: recovery: copied: "[ kopiert ]" continue: Weiter diff --git a/config/locales/en.yml b/config/locales/en.yml index f78235ae00f..ecc5ab1974d 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -26,7 +26,10 @@ en: locale_name: English none: None not_found: Not Found + api_gem_not_found: This gem could not be found api_key_forbidden: The API key doesn't have access + api_key_soft_deleted: An invalid API key cannot be used. Please delete it and create a new one. + api_key_insufficient_scope: This API key cannot perform the specified action on this gem. please_sign_up: Access Denied. Please sign up for an account at https://rubygems.org please_sign_in: Please sign in to continue. otp_incorrect: Your OTP code is incorrect. Please check it and retry. @@ -427,6 +430,22 @@ en: strong_mfa_level_required_html: For protection of your account and your gems, you are required to change your MFA level to "UI and gem signin" or "UI and API". Please read our blog post for more details. strong_mfa_level_recommended: For protection of your account and your gems, we encourage you to change your MFA level to "UI and gem signin" or "UI and API". Your account will be required to have MFA enabled on one of these levels in the future. setup_webauthn_html: 🎉 We now support security devices! Improve your account security by setting up a new device. Learn more! + api: + mfa_required: Gem requires MFA enabled; You do not have MFA enabled yet. + mfa_required_not_yet_enabled: | + [ERROR] For protection of your account and your gems, you are required to set up multi-factor authentication at https://rubygems.org/totp/new. + + Please read our blog post for more details (https://blog.rubygems.org/2022/08/15/requiring-mfa-on-popular-gems.html). + mfa_required_weak_level_enabled: | + [ERROR] For protection of your account and your gems, you are required to change your MFA level to 'UI and gem signin' or 'UI and API' at https://rubygems.org/settings/edit. + + Please read our blog post for more details (https://blog.rubygems.org/2022/08/15/requiring-mfa-on-popular-gems.html). + mfa_recommended_not_yet_enabled: | + [WARNING] For protection of your account and gems, we encourage you to set up multi-factor authentication at https://rubygems.org/totp/new. + Your account will be required to have MFA enabled in the future. + mfa_recommended_weak_level_enabled: | + [WARNING] For protection of your account and gems, we encourage you to change your multi-factor authentication level to 'UI and gem signin' or 'UI and API' at https://rubygems.org/settings/edit. + Your account will be required to have MFA enabled on one of these levels in the future. recovery: copied: "[ copied ]" continue: Continue diff --git a/config/locales/es.yml b/config/locales/es.yml index 17af540ada5..6b8649a9742 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -26,7 +26,10 @@ es: locale_name: Español none: Ninguno not_found: No encontrado + api_gem_not_found: api_key_forbidden: La clave API no tiene acceso + api_key_soft_deleted: + api_key_insufficient_scope: please_sign_up: Acceso denegado. Por favor regístrate en https://rubygems.org please_sign_in: Por favor, ingresa en tu cuenta para continuar. otp_incorrect: Tu código OTP es incorrecto. Por favor verifícalo y prueba nuevamente. @@ -496,6 +499,12 @@ es: setup_webauthn_html: "\U0001F389 ¡Ahora soportamos dispositivos de seguridad! Aumenta la seguridad de tu cuenta configurando un nuevo dispositivo." + api: + mfa_required: + mfa_required_not_yet_enabled: + mfa_required_weak_level_enabled: + mfa_recommended_not_yet_enabled: + mfa_recommended_weak_level_enabled: recovery: copied: "[ copiado ]" continue: Continuar @@ -670,7 +679,8 @@ es: %{unconfirmed_email} enter_password: Por favor introduce tu contraseña optional_full_name: Opcional. Será mostrado en tu perfil público - optional_twitter_username: Usuario de X opcional. Será mostrado en tu perfil público + optional_twitter_username: Usuario de X opcional. Será mostrado en tu perfil + público twitter_username: Usuario title: Editar perfil delete: diff --git a/config/locales/fr.yml b/config/locales/fr.yml index a309c89e946..5e9e9fa2be8 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -27,7 +27,10 @@ fr: locale_name: Français none: not_found: Introuvable + api_gem_not_found: api_key_forbidden: + api_key_soft_deleted: + api_key_insufficient_scope: please_sign_up: Accès refusé. Inscrivez-vous sur https://rubygems.org please_sign_in: otp_incorrect: @@ -447,6 +450,12 @@ fr: strong_mfa_level_required_html: strong_mfa_level_recommended: setup_webauthn_html: + api: + mfa_required: + mfa_required_not_yet_enabled: + mfa_required_weak_level_enabled: + mfa_recommended_not_yet_enabled: + mfa_recommended_weak_level_enabled: recovery: copied: continue: Continuer diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 63d23c96f36..ea622b776d7 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -20,7 +20,10 @@ ja: locale_name: 日本語 none: なし not_found: 見つかりませんでした + api_gem_not_found: api_key_forbidden: APIキーにアクセス権がありません + api_key_soft_deleted: + api_key_insufficient_scope: please_sign_up: アクセスが拒否されました。https://rubygems.org でアカウント登録を行ってください。 please_sign_in: サインインしてお進みください。 otp_incorrect: OTPのコードが正しくありません。ご確認の上再試行してください。 @@ -428,6 +431,12 @@ ja: strong_mfa_level_recommended: アカウントとgemの保護のため、MFAの水準を「UIとgemのサインイン」または「UIとAPI」に変更することをお勧めします。将来のアカウントはこれらの水準のどちらか1つにMFAが有効になっていることが必須になります。 setup_webauthn_html: "\U0001F389 セキュリティ機器に対応しました!新しい機器を設定してアカウントのセキュリティを向上しましょう。詳細はこちら!" + api: + mfa_required: + mfa_required_not_yet_enabled: + mfa_required_weak_level_enabled: + mfa_recommended_not_yet_enabled: + mfa_recommended_weak_level_enabled: recovery: copied: "[ コピーしました ]" continue: 続ける diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 269bb17ba8a..9bae60eafd8 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -19,7 +19,10 @@ nl: locale_name: Nederlands none: Geen not_found: Niet gevonden + api_gem_not_found: api_key_forbidden: + api_key_soft_deleted: + api_key_insufficient_scope: please_sign_up: Toegang geweigerd. Schrijf je in voor een account op https://rubygems.org please_sign_in: otp_incorrect: @@ -432,6 +435,12 @@ nl: strong_mfa_level_required_html: strong_mfa_level_recommended: setup_webauthn_html: + api: + mfa_required: + mfa_required_not_yet_enabled: + mfa_required_weak_level_enabled: + mfa_recommended_not_yet_enabled: + mfa_recommended_weak_level_enabled: recovery: copied: continue: diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 57d2269b7f7..73cc4a7eef1 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -25,7 +25,10 @@ pt-BR: locale_name: Português do Brasil none: Nenhum not_found: Não encontrado + api_gem_not_found: api_key_forbidden: + api_key_soft_deleted: + api_key_insufficient_scope: please_sign_up: Acesso Negado. Por favor se registre em https://rubygems.org please_sign_in: Por favor, faça login em sua conta para continuar. otp_incorrect: Seu código OTP está incorreto. Por favor, verifique-o e tente novamente. @@ -443,6 +446,12 @@ pt-BR: strong_mfa_level_required_html: strong_mfa_level_recommended: setup_webauthn_html: + api: + mfa_required: + mfa_required_not_yet_enabled: + mfa_required_weak_level_enabled: + mfa_recommended_not_yet_enabled: + mfa_recommended_weak_level_enabled: recovery: copied: continue: diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index e52330c68de..9ad807e5c76 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -21,7 +21,10 @@ zh-CN: locale_name: 简体中文 none: 无 not_found: 未找到 + api_gem_not_found: api_key_forbidden: API 密钥没有访问权限 + api_key_soft_deleted: + api_key_insufficient_scope: please_sign_up: 拒绝访问。请在 https://rubygems.org 上注册一个账号。 please_sign_in: 请先登录以继续 otp_incorrect: 您的 OTP 码不正确。请检查后重试。 @@ -436,6 +439,12 @@ zh-CN: strong_mfa_level_recommended: 为了保护您的帐户和您的 Gem,我们建议您将您的多因素验证级别更改为 "UI and gem signin" 或 "UI and API"。在将来,您的帐户将被要求在其中某一个级别上启用多因素验证。 setup_webauthn_html: + api: + mfa_required: + mfa_required_not_yet_enabled: + mfa_required_weak_level_enabled: + mfa_recommended_not_yet_enabled: + mfa_recommended_weak_level_enabled: recovery: copied: "[ 已复制 ]" continue: 继续 diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index 0ce6860de28..a459d5180a8 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -20,7 +20,10 @@ zh-TW: locale_name: 正體中文 none: 無 not_found: 沒有找到 + api_gem_not_found: api_key_forbidden: API 金鑰沒有存取權限 + api_key_soft_deleted: + api_key_insufficient_scope: please_sign_up: 存取遭拒。請先在 https://rubygems.org 上註冊帳號 please_sign_in: 請登入以繼續。 otp_incorrect: 您的 OTP 碼不正確。請檢查後再試一次。 @@ -431,6 +434,12 @@ zh-TW: 或 "使用者介面和 API"。未來我們將強制要求所有帳號將設為上述 MFA 等級。 setup_webauthn_html: "\U0001F389 我們現在支援安全裝置了!設定新的裝置來提升您的帳號安全。了解詳情!" + api: + mfa_required: + mfa_required_not_yet_enabled: + mfa_required_weak_level_enabled: + mfa_recommended_not_yet_enabled: + mfa_recommended_weak_level_enabled: recovery: copied: "[ 已複製 ]" continue: 繼續 diff --git a/test/functional/api/v1/api_keys_controller_test.rb b/test/functional/api/v1/api_keys_controller_test.rb index 62066783a9b..b0ba00d58e5 100644 --- a/test/functional/api/v1/api_keys_controller_test.rb +++ b/test/functional/api/v1/api_keys_controller_test.rb @@ -469,12 +469,7 @@ def self.should_expect_otp_for_update should "deny access" do assert_response :forbidden - mfa_error = <<~ERROR.chomp - [ERROR] For protection of your account and your gems, you are required to set up multi-factor authentication \ - at https://rubygems.org/totp/new. - - Please read our blog post for more details (https://blog.rubygems.org/2022/08/15/requiring-mfa-on-popular-gems.html). - ERROR + mfa_error = I18n.t("multifactor_auths.api.mfa_required_not_yet_enabled").chomp assert_match mfa_error, @response.body end @@ -488,12 +483,7 @@ def self.should_expect_otp_for_update should "deny access" do assert_response :forbidden - mfa_error = <<~ERROR.chomp - [ERROR] For protection of your account and your gems, you are required to change your MFA level to 'UI and gem signin' or 'UI and API' \ - at https://rubygems.org/settings/edit. - - Please read our blog post for more details (https://blog.rubygems.org/2022/08/15/requiring-mfa-on-popular-gems.html). - ERROR + mfa_error = I18n.t("multifactor_auths.api.mfa_required_weak_level_enabled").chomp assert_match mfa_error, @response.body end diff --git a/test/functional/api/v1/deletions_controller_test.rb b/test/functional/api/v1/deletions_controller_test.rb index 2bd2d47a6e0..d10cbef1274 100644 --- a/test/functional/api/v1/deletions_controller_test.rb +++ b/test/functional/api/v1/deletions_controller_test.rb @@ -189,12 +189,7 @@ class Api::V1::DeletionsControllerTest < ActionController::TestCase should respond_with :forbidden should "show error message" do - mfa_error = <<~ERROR.chomp - [ERROR] For protection of your account and your gems, you are required to set up multi-factor authentication \ - at https://rubygems.org/totp/new. - - Please read our blog post for more details (https://blog.rubygems.org/2022/08/15/requiring-mfa-on-popular-gems.html). - ERROR + mfa_error = I18n.t("multifactor_auths.api.mfa_required_not_yet_enabled").chomp assert_includes @response.body, mfa_error end @@ -209,12 +204,7 @@ class Api::V1::DeletionsControllerTest < ActionController::TestCase should respond_with :forbidden should "show error message" do - mfa_error = <<~ERROR.chomp - [ERROR] For protection of your account and your gems, you are required to change your MFA level to 'UI and gem signin' or 'UI and API' \ - at https://rubygems.org/settings/edit. - - Please read our blog post for more details (https://blog.rubygems.org/2022/08/15/requiring-mfa-on-popular-gems.html). - ERROR + mfa_error = I18n.t("multifactor_auths.api.mfa_required_weak_level_enabled").chomp assert_includes @response.body, mfa_error end @@ -290,12 +280,7 @@ class Api::V1::DeletionsControllerTest < ActionController::TestCase delete :create, params: { gem_name: gem[:name], version: gem[:version] } assert_response gem[:deletion_status] - mfa_warning = <<~WARN.chomp - - - [WARNING] For protection of your account and gems, we encourage you to set up multi-factor authentication \ - at https://rubygems.org/totp/new. Your account will be required to have MFA enabled in the future. - WARN + mfa_warning = "\n\n#{I18n.t('multifactor_auths.api.mfa_recommended_not_yet_enabled')}".chomp assert_includes @response.body, mfa_warning end @@ -312,13 +297,7 @@ class Api::V1::DeletionsControllerTest < ActionController::TestCase delete :create, params: { gem_name: gem[:name], version: gem[:version] } assert_response gem[:deletion_status] - mfa_warning = <<~WARN.chomp - - - [WARNING] For protection of your account and gems, we encourage you to change your multi-factor authentication \ - level to 'UI and gem signin' or 'UI and API' at https://rubygems.org/settings/edit. \ - Your account will be required to have MFA enabled on one of these levels in the future. - WARN + mfa_warning = "\n\n#{I18n.t('multifactor_auths.api.mfa_recommended_weak_level_enabled')}".chomp assert_includes @response.body, mfa_warning end @@ -336,9 +315,8 @@ class Api::V1::DeletionsControllerTest < ActionController::TestCase delete :create, params: { gem_name: gem[:name], version: gem[:version] } assert_response gem[:deletion_status] - mfa_warning = "[WARNING] For protection of your account and gems" - - refute_includes @response.body, mfa_warning + refute_includes @response.body, I18n.t("multifactor_auths.api.mfa_recommended_not_yet_enabled").chomp + refute_includes @response.body, I18n.t("multifactor_auths.api.mfa_recommended_weak_level_enabled").chomp end end end @@ -354,9 +332,8 @@ class Api::V1::DeletionsControllerTest < ActionController::TestCase delete :create, params: { gem_name: gem[:name], version: gem[:version] } assert_response gem[:deletion_status] - mfa_warning = "[WARNING] For protection of your account and gems" - - refute_includes @response.body, mfa_warning + refute_includes @response.body, I18n.t("multifactor_auths.api.mfa_recommended_not_yet_enabled").chomp + refute_includes @response.body, I18n.t("multifactor_auths.api.mfa_recommended_weak_level_enabled").chomp end end end diff --git a/test/functional/api/v1/owners_controller_test.rb b/test/functional/api/v1/owners_controller_test.rb index 6a2369bc2ca..7f5e8df6e40 100644 --- a/test/functional/api/v1/owners_controller_test.rb +++ b/test/functional/api/v1/owners_controller_test.rb @@ -401,12 +401,8 @@ def self.should_respond_to(format) post :create, params: { rubygem_id: @rubygem.slug, email: email } assert_equal 403, @response.status - mfa_error = <<~ERROR.chomp - [ERROR] For protection of your account and your gems, you are required to set up multi-factor authentication \ - at https://rubygems.org/totp/new. + mfa_error = I18n.t("multifactor_auths.api.mfa_required_not_yet_enabled").chomp - Please read our blog post for more details (https://blog.rubygems.org/2022/08/15/requiring-mfa-on-popular-gems.html). - ERROR assert_includes @response.body, mfa_error end end @@ -422,12 +418,8 @@ def self.should_respond_to(format) post :create, params: { rubygem_id: @rubygem.slug, email: email } assert_equal 403, @response.status - mfa_error = <<~ERROR.chomp - [ERROR] For protection of your account and your gems, you are required to change your MFA level to 'UI and gem signin' or 'UI and API' \ - at https://rubygems.org/settings/edit. + mfa_error = I18n.t("multifactor_auths.api.mfa_required_weak_level_enabled").chomp - Please read our blog post for more details (https://blog.rubygems.org/2022/08/15/requiring-mfa-on-popular-gems.html). - ERROR assert_includes @response.body, mfa_error end end @@ -473,12 +465,7 @@ def self.should_respond_to(format) should "include mfa setup warning" do @emails.each do |email| post :create, params: { rubygem_id: @rubygem.slug, email: email } - mfa_warning = <<~WARN.chomp - - - [WARNING] For protection of your account and gems, we encourage you to set up multi-factor authentication \ - at https://rubygems.org/totp/new. Your account will be required to have MFA enabled in the future. - WARN + mfa_warning = "\n\n#{I18n.t('multifactor_auths.api.mfa_recommended_not_yet_enabled')}".chomp assert_includes @response.body, mfa_warning end @@ -493,13 +480,7 @@ def self.should_respond_to(format) should "include change mfa level warning" do @emails.each do |email| post :create, params: { rubygem_id: @rubygem.slug, email: email } - mfa_warning = <<~WARN.chomp - - - [WARNING] For protection of your account and gems, we encourage you to change your multi-factor authentication \ - level to 'UI and gem signin' or 'UI and API' at https://rubygems.org/settings/edit. \ - Your account will be required to have MFA enabled on one of these levels in the future. - WARN + mfa_warning = "\n\n#{I18n.t('multifactor_auths.api.mfa_recommended_weak_level_enabled')}".chomp assert_includes @response.body, mfa_warning end @@ -514,9 +495,9 @@ def self.should_respond_to(format) should "not include MFA warnings" do @emails.each do |email| post :create, params: { rubygem_id: @rubygem.slug, email: email } - mfa_warning = "[WARNING] For protection of your account and gems" - refute_includes @response.body, mfa_warning + refute_includes @response.body, I18n.t("multifactor_auths.api.mfa_recommended_not_yet_enabled").chomp + refute_includes @response.body, I18n.t("multifactor_auths.api.mfa_recommended_weak_level_enabled").chomp end end end @@ -530,9 +511,9 @@ def self.should_respond_to(format) should "not include mfa warnings" do @emails.each do |email| post :create, params: { rubygem_id: @rubygem.slug, email: email } - mfa_warning = "[WARNING] For protection of your account and gems" - refute_includes @response.body, mfa_warning + refute_includes @response.body, I18n.t("multifactor_auths.api.mfa_recommended_not_yet_enabled").chomp + refute_includes @response.body, I18n.t("multifactor_auths.api.mfa_recommended_weak_level_enabled").chomp end end end @@ -784,12 +765,8 @@ def self.should_respond_to(format) delete :destroy, params: { rubygem_id: @rubygem.slug, email: email } assert_equal 403, response.status - mfa_error = <<~ERROR.chomp - [ERROR] For protection of your account and your gems, you are required to set up multi-factor authentication \ - at https://rubygems.org/totp/new. + mfa_error = I18n.t("multifactor_auths.api.mfa_required_not_yet_enabled").chomp - Please read our blog post for more details (https://blog.rubygems.org/2022/08/15/requiring-mfa-on-popular-gems.html). - ERROR assert_includes @response.body, mfa_error end end @@ -805,12 +782,8 @@ def self.should_respond_to(format) delete :destroy, params: { rubygem_id: @rubygem.slug, email: email } assert_equal 403, @response.status - mfa_error = <<~ERROR.chomp - [ERROR] For protection of your account and your gems, you are required to change your MFA level to 'UI and gem signin' or 'UI and API' \ - at https://rubygems.org/settings/edit. + mfa_error = I18n.t("multifactor_auths.api.mfa_required_weak_level_enabled").chomp - Please read our blog post for more details (https://blog.rubygems.org/2022/08/15/requiring-mfa-on-popular-gems.html). - ERROR assert_includes @response.body, mfa_error end end @@ -856,12 +829,7 @@ def self.should_respond_to(format) should "include mfa setup warning" do @emails.each do |email| delete :destroy, params: { rubygem_id: @rubygem.slug, email: email } - mfa_warning = <<~WARN.chomp - - - [WARNING] For protection of your account and gems, we encourage you to set up multi-factor authentication \ - at https://rubygems.org/totp/new. Your account will be required to have MFA enabled in the future. - WARN + mfa_warning = "\n\n#{I18n.t('multifactor_auths.api.mfa_recommended_not_yet_enabled')}".chomp assert_includes @response.body, mfa_warning end @@ -876,13 +844,7 @@ def self.should_respond_to(format) should "include change mfa level warning" do @emails.each do |email| delete :destroy, params: { rubygem_id: @rubygem.slug, email: email } - mfa_warning = <<~WARN.chomp - - - [WARNING] For protection of your account and gems, we encourage you to change your multi-factor authentication \ - level to 'UI and gem signin' or 'UI and API' at https://rubygems.org/settings/edit. \ - Your account will be required to have MFA enabled on one of these levels in the future. - WARN + mfa_warning = "\n\n#{I18n.t('multifactor_auths.api.mfa_recommended_weak_level_enabled')}".chomp assert_includes @response.body, mfa_warning end @@ -897,9 +859,9 @@ def self.should_respond_to(format) should "not include mfa warnings" do @emails.each do |email| delete :destroy, params: { rubygem_id: @rubygem.slug, email: email } - mfa_warning = "[WARNING] For protection of your account and gems" - refute_includes @response.body, mfa_warning + refute_includes @response.body, I18n.t("multifactor_auths.api.mfa_recommended_not_yet_enabled").chomp + refute_includes @response.body, I18n.t("multifactor_auths.api.mfa_recommended_weak_level_enabled").chomp end end end @@ -913,9 +875,9 @@ def self.should_respond_to(format) should "not include mfa warnings" do @emails.each do |email| delete :destroy, params: { rubygem_id: @rubygem.slug, email: email } - mfa_warning = "[WARNING] For protection of your account and gems" - refute_includes @response.body, mfa_warning + refute_includes @response.body, I18n.t("multifactor_auths.api.mfa_recommended_not_yet_enabled").chomp + refute_includes @response.body, I18n.t("multifactor_auths.api.mfa_recommended_weak_level_enabled").chomp end end end diff --git a/test/functional/api/v1/profiles_controller_test.rb b/test/functional/api/v1/profiles_controller_test.rb index 401046e4113..b39f0d32969 100644 --- a/test/functional/api/v1/profiles_controller_test.rb +++ b/test/functional/api/v1/profiles_controller_test.rb @@ -27,15 +27,6 @@ def assert_mfa_info_included(mfa_level) assert_match mfa_level, @response.body end - def assert_warning_included(expected_warning) - assert response_body.key?("warning") - assert_match expected_warning, response_body["warning"].to_s - end - - def refute_warning_included(expected_warning) - refute_match expected_warning, response_body["warning"].to_s - end - def refute_mfa_info_included(mfa_level) refute response_body.key?("mfa") refute_match mfa_level, @response.body @@ -101,11 +92,9 @@ def refute_mfa_info_included(mfa_level) context "when mfa is disabled" do should "include warning" do - expected_warning = - "For protection of your account and gems, we encourage you to set up multi-factor authentication " \ - "at https://rubygems.org/totp/new. Your account will be required to have MFA enabled in the future." + expected_warning = I18n.t("multifactor_auths.api.mfa_recommended_not_yet_enabled").chomp - assert_warning_included(expected_warning) + assert_includes response_body["warning"].to_s, expected_warning end end @@ -117,12 +106,9 @@ def refute_mfa_info_included(mfa_level) end should "include warning" do - expected_warning = - "For protection of your account and gems, we encourage you to change your multi-factor authentication " \ - "level to 'UI and gem signin' or 'UI and API' at https://rubygems.org/settings/edit. " \ - "Your account will be required to have MFA enabled on one of these levels in the future." + expected_warning = I18n.t("multifactor_auths.api.mfa_recommended_weak_level_enabled").chomp - assert_warning_included(expected_warning) + assert_includes response_body["warning"].to_s, expected_warning end end @@ -133,10 +119,9 @@ def refute_mfa_info_included(mfa_level) end should "not include warning in user json" do - unexpected_warning = - "For protection of your account and gems" + unexpected_warning = "For protection of your account and gems" - refute_warning_included(unexpected_warning) + refute_includes response_body["warning"].to_s, unexpected_warning end end @@ -147,10 +132,9 @@ def refute_mfa_info_included(mfa_level) end should "not include warning" do - unexpected_warning = - "For protection of your account and gems" + unexpected_warning = "For protection of your account and gems" - refute_warning_included(unexpected_warning) + refute_includes response_body["warning"].to_s, unexpected_warning end end end diff --git a/test/functional/api/v1/rubygems_controller_test.rb b/test/functional/api/v1/rubygems_controller_test.rb index 8c644632e2e..cf60b05c4c4 100644 --- a/test/functional/api/v1/rubygems_controller_test.rb +++ b/test/functional/api/v1/rubygems_controller_test.rb @@ -560,12 +560,7 @@ def self.should_respond_to(format) should respond_with :forbidden should "show error message" do - mfa_error = <<~ERROR.chomp - [ERROR] For protection of your account and your gems, you are required to set up multi-factor authentication \ - at https://rubygems.org/totp/new. - - Please read our blog post for more details (https://blog.rubygems.org/2022/08/15/requiring-mfa-on-popular-gems.html). - ERROR + mfa_error = I18n.t("multifactor_auths.api.mfa_required_not_yet_enabled").chomp assert_includes @response.body, mfa_error end @@ -580,12 +575,7 @@ def self.should_respond_to(format) should respond_with :forbidden should "show error message" do - mfa_error = <<~ERROR.chomp - [ERROR] For protection of your account and your gems, you are required to change your MFA level to 'UI and gem signin' or 'UI and API' \ - at https://rubygems.org/settings/edit. - - Please read our blog post for more details (https://blog.rubygems.org/2022/08/15/requiring-mfa-on-popular-gems.html). - ERROR + mfa_error = I18n.t("multifactor_auths.api.mfa_required_weak_level_enabled").chomp assert_includes @response.body, mfa_error end @@ -600,7 +590,8 @@ def self.should_respond_to(format) should respond_with :success should "not show error message" do - refute_includes @response.body, "For protection of your account and your gems" + refute_includes @response.body, I18n.t("multifactor_auths.api.mfa_required_not_yet_enabled").chomp + refute_includes @response.body, I18n.t("multifactor_auths.api.mfa_required_weak_level_enabled").chomp end end @@ -614,7 +605,8 @@ def self.should_respond_to(format) should respond_with :success should "not show error message" do - refute_includes @response.body, "For protection of your account and your gems" + refute_includes @response.body, I18n.t("multifactor_auths.api.mfa_required_not_yet_enabled").chomp + refute_includes @response.body, I18n.t("multifactor_auths.api.mfa_required_weak_level_enabled").chomp end end end @@ -630,14 +622,7 @@ def self.should_respond_to(format) end should "include mfa setup warning" do - mfa_warning = <<~WARN.chomp - - - [WARNING] For protection of your account and gems, we encourage you to set up multi-factor authentication \ - at https://rubygems.org/totp/new. Your account will be required to have MFA enabled in the future. - WARN - - assert_includes @response.body, mfa_warning + assert_includes @response.body, I18n.t("multifactor_auths.api.mfa_recommended_not_yet_enabled").chomp end end @@ -648,15 +633,7 @@ def self.should_respond_to(format) end should "include change mfa level warning" do - mfa_warning = <<~WARN.chomp - - - [WARNING] For protection of your account and gems, we encourage you to change your multi-factor authentication \ - level to 'UI and gem signin' or 'UI and API' at https://rubygems.org/settings/edit. \ - Your account will be required to have MFA enabled on one of these levels in the future. - WARN - - assert_includes @response.body, mfa_warning + assert_includes @response.body, I18n.t("multifactor_auths.api.mfa_recommended_weak_level_enabled").chomp end end @@ -669,9 +646,8 @@ def self.should_respond_to(format) should respond_with :success should "not include mfa warning" do - mfa_warning = "[WARNING] For protection of your account and gems" - - refute_includes @response.body, mfa_warning + refute_includes @response.body, I18n.t("multifactor_auths.api.mfa_recommended_not_yet_enabled").chomp + refute_includes @response.body, I18n.t("multifactor_auths.api.mfa_recommended_weak_level_enabled").chomp end end @@ -684,9 +660,8 @@ def self.should_respond_to(format) should respond_with :success should "not include mfa warning" do - mfa_warning = "[WARNING] For protection of your account and gems" - - refute_includes @response.body, mfa_warning + refute_includes @response.body, I18n.t("multifactor_auths.api.mfa_recommended_not_yet_enabled").chomp + refute_includes @response.body, I18n.t("multifactor_auths.api.mfa_recommended_weak_level_enabled").chomp end end end @@ -786,8 +761,8 @@ def self.should_respond_to(format) end should respond_with :forbidden - should "return body that starts with denied access message" do - assert @response.body.start_with?("The API key doesn't have access") + should "return body that includes the denied access message" do + assert_includes @response.body, "This API key cannot perform the specified action on this gem." end end end diff --git a/test/models/user/with_private_fields_test.rb b/test/models/user/with_private_fields_test.rb index 2c6b15b19ce..2741aef1382 100644 --- a/test/models/user/with_private_fields_test.rb +++ b/test/models/user/with_private_fields_test.rb @@ -14,11 +14,9 @@ class User::WithPrivateFieldsTest < ActiveSupport::TestCase context "when mfa is disabled" do should "include warning in user json" do - expected_notice = - "[WARNING] For protection of your account and gems, we encourage you to set up multi-factor authentication " \ - "at https://rubygems.org/totp/new. Your account will be required to have MFA enabled in the future." + expected_notice = I18n.t("multifactor_auths.api.mfa_recommended_not_yet_enabled").chomp - assert_match expected_notice, @user.to_json + assert_includes JSON.parse(@user.to_json)["warning"], expected_notice end end @@ -29,12 +27,9 @@ class User::WithPrivateFieldsTest < ActiveSupport::TestCase end should "include warning in user json" do - expected_notice = - "[WARNING] For protection of your account and gems, we encourage you to change your multi-factor authentication " \ - "level to 'UI and gem signin' or 'UI and API' at https://rubygems.org/settings/edit. " \ - "Your account will be required to have MFA enabled on one of these levels in the future." + expected_notice = I18n.t("multifactor_auths.api.mfa_recommended_weak_level_enabled").chomp - assert_match expected_notice, @user.to_json + assert_includes JSON.parse(@user.to_json)["warning"], expected_notice end end @@ -44,10 +39,9 @@ class User::WithPrivateFieldsTest < ActiveSupport::TestCase end should "not include warning in user json" do - unexpected_notice = - "[WARNING] For protection of your account and gems" + unexpected_notice = I18n.t("multifactor_auths.api.mfa_recommended_not_yet_enabled").chomp - refute_match unexpected_notice, @user.to_json + refute_includes JSON.parse(@user.to_json)["warning"].to_s, unexpected_notice end end @@ -57,10 +51,9 @@ class User::WithPrivateFieldsTest < ActiveSupport::TestCase end should "not include warning in user json" do - unexpected_notice = - "[WARNING] For protection of your account and gems" + unexpected_notice = I18n.t("multifactor_auths.api.mfa_recommended_weak_level_enabled").chomp - refute_match unexpected_notice, @user.to_json + refute_includes JSON.parse(@user.to_json)["warning"].to_s, unexpected_notice end end end From faeab4ee53a0faf1fe32292d49c24efeae056fdd Mon Sep 17 00:00:00 2001 From: Martin Emde Date: Thu, 11 Jul 2024 17:38:29 -0700 Subject: [PATCH 014/381] Add no-op policies to api actions (#4884) --- app/controllers/api/base_controller.rb | 1 + .../api/v1/deletions_controller.rb | 1 + app/controllers/api/v1/owners_controller.rb | 2 ++ app/controllers/api/v1/rubygems_controller.rb | 2 ++ .../api/v1/web_hooks_controller.rb | 7 +++++-- app/policies/api/rubygem_policy.rb | 20 +++++++++++++++++++ app/policies/api/web_hook_policy.rb | 20 +++++++++++++++++++ 7 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 app/policies/api/web_hook_policy.rb diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb index 5650be62848..5ae17b2a49d 100644 --- a/app/controllers/api/base_controller.rb +++ b/app/controllers/api/base_controller.rb @@ -72,6 +72,7 @@ def policy_scope(scope) end def authorize(record, query = nil) + return if record.nil? # not found is handled by the action super(Array.wrap(record).prepend(:api), query) end diff --git a/app/controllers/api/v1/deletions_controller.rb b/app/controllers/api/v1/deletions_controller.rb index 4ead8e71c2e..5f5590fa4e1 100644 --- a/app/controllers/api/v1/deletions_controller.rb +++ b/app/controllers/api/v1/deletions_controller.rb @@ -9,6 +9,7 @@ class Api::V1::DeletionsController < Api::BaseController before_action :verify_mfa_requirement def create + authorize @rubygem, :yank? @deletion = @api_key.user.deletions.build(version: @version) if @deletion.save StatsD.increment "yank.success" diff --git a/app/controllers/api/v1/owners_controller.rb b/app/controllers/api/v1/owners_controller.rb index b6203b73be0..2ee1b5fc215 100644 --- a/app/controllers/api/v1/owners_controller.rb +++ b/app/controllers/api/v1/owners_controller.rb @@ -15,6 +15,7 @@ def show end def create + authorize @rubygem, :add_owner? return render_forbidden(t(:api_key_forbidden)) unless @api_key.can_add_owner? owner = User.find_by_name(email_param) @@ -34,6 +35,7 @@ def create end def destroy + authorize @rubygem, :remove_owner? return render_forbidden(t(:api_key_forbidden)) unless @api_key.can_remove_owner? owner = @rubygem.owners_including_unconfirmed.find_by_name(email_param) diff --git a/app/controllers/api/v1/rubygems_controller.rb b/app/controllers/api/v1/rubygems_controller.rb index 54a27a71402..c7c29cf8529 100644 --- a/app/controllers/api/v1/rubygems_controller.rb +++ b/app/controllers/api/v1/rubygems_controller.rb @@ -8,6 +8,7 @@ class Api::V1::RubygemsController < Api::BaseController after_action :cors_set_access_control_headers, only: :show def index + authorize Rubygem, :index? return render_forbidden(t(:api_key_insufficient_scope)) unless @api_key.can_index_rubygems? @rubygems = @api_key.user.rubygems.with_versions @@ -33,6 +34,7 @@ def show end def create + authorize Rubygem, :create? return render_forbidden(t(:api_key_insufficient_scope)) unless @api_key.can_push_rubygem? gemcutter = Pusher.new(@api_key, request.body, request:) diff --git a/app/controllers/api/v1/web_hooks_controller.rb b/app/controllers/api/v1/web_hooks_controller.rb index ac5a63726c2..20ebff61aef 100644 --- a/app/controllers/api/v1/web_hooks_controller.rb +++ b/app/controllers/api/v1/web_hooks_controller.rb @@ -5,6 +5,7 @@ class Api::V1::WebHooksController < Api::BaseController before_action :find_rubygem_by_name, :set_url, except: :index def index + authorize WebHook respond_to do |format| format.json { render json: @api_key.user.all_hooks } format.yaml { render yaml: @api_key.user.all_hooks } @@ -12,7 +13,7 @@ def index end def create - webhook = @api_key.user.web_hooks.build(url: @url, rubygem: @rubygem) + webhook = authorize @api_key.user.web_hooks.build(url: @url, rubygem: @rubygem) if webhook.save render(plain: webhook.success_message, status: :created) else @@ -21,7 +22,7 @@ def create end def remove - webhook = @api_key.user.web_hooks.find_by_rubygem_id_and_url(@rubygem&.id, @url) + webhook = authorize @api_key.user.web_hooks.find_by_rubygem_id_and_url(@rubygem&.id, @url) if webhook&.destroy render(plain: webhook.removed_message) else @@ -33,6 +34,8 @@ def fire webhook = @api_key.user.web_hooks.new(url: @url) @rubygem ||= Rubygem.find_by_name("gemcutter") + authorize webhook + if webhook.fire(request.protocol.delete("://"), request.host_with_port, @rubygem.most_recent_version, delayed: false) render plain: webhook.deployed_message(@rubygem) diff --git a/app/policies/api/rubygem_policy.rb b/app/policies/api/rubygem_policy.rb index 9c52e5273b6..f198211f833 100644 --- a/app/policies/api/rubygem_policy.rb +++ b/app/policies/api/rubygem_policy.rb @@ -4,6 +4,26 @@ class Scope < Api::ApplicationPolicy::Scope alias rubygem record + def index? + true + end + + def create? + true + end + + def yank? + true + end + + def add_owner? + true + end + + def remove_owner? + true + end + def show_trusted_publishers? api_key_scope?(:configure_trusted_publishers, rubygem) && user_policy!.show_trusted_publishers? end diff --git a/app/policies/api/web_hook_policy.rb b/app/policies/api/web_hook_policy.rb new file mode 100644 index 00000000000..ab90e3dc3b5 --- /dev/null +++ b/app/policies/api/web_hook_policy.rb @@ -0,0 +1,20 @@ +class Api::WebHookPolicy < Api::ApplicationPolicy + class Scope < Api::ApplicationPolicy::Scope + end + + def index? + true + end + + def create? + true + end + + def fire? + true + end + + def remove? + true + end +end From 8df57dfa141a2eb1b358b14896058164c957242b Mon Sep 17 00:00:00 2001 From: Andre Arko Date: Sat, 29 Jun 2024 20:02:36 -0700 Subject: [PATCH 015/381] support puma-dev and .pumaenv.local --- .gitignore | 1 + .pumaenv | 1 + config/environments/development.rb | 2 ++ 3 files changed, 4 insertions(+) create mode 100644 .pumaenv diff --git a/.gitignore b/.gitignore index 1f91c4ccd45..fcfb8481101 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ latest_dump coverage REVISION /.env* +/.pumaenv.local /doc/erd.* /app/assets/builds/* diff --git a/.pumaenv b/.pumaenv new file mode 100644 index 00000000000..57afa2d530a --- /dev/null +++ b/.pumaenv @@ -0,0 +1 @@ +[[ -e ".pumaenv.local" ]] && source .pumaenv.local diff --git a/config/environments/development.rb b/config/environments/development.rb index 63cbd9de3ce..42bbef4f7de 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -129,4 +129,6 @@ config.active_record.verbose_query_logs = false config.action_view.cache_template_loading = true end + + config.hosts << "rubygems.test" end From 7ec974b5ed0d38b66ae52c532aa213ccd493094c Mon Sep 17 00:00:00 2001 From: Andre Arko Date: Sat, 29 Jun 2024 20:03:05 -0700 Subject: [PATCH 016/381] generate some orgs --- app/avo/resources/org_resource.rb | 14 ++++++++++++++ app/controllers/avo/orgs_controller.rb | 4 ++++ app/models/org.rb | 2 ++ db/migrate/20240630025625_create_orgs.rb | 11 +++++++++++ db/schema.rb | 8 ++++++++ test/factories/orgs.rb | 7 +++++++ test/models/org_test.rb | 7 +++++++ 7 files changed, 53 insertions(+) create mode 100644 app/avo/resources/org_resource.rb create mode 100644 app/controllers/avo/orgs_controller.rb create mode 100644 app/models/org.rb create mode 100644 db/migrate/20240630025625_create_orgs.rb create mode 100644 test/factories/orgs.rb create mode 100644 test/models/org_test.rb diff --git a/app/avo/resources/org_resource.rb b/app/avo/resources/org_resource.rb new file mode 100644 index 00000000000..7f6d95a8e69 --- /dev/null +++ b/app/avo/resources/org_resource.rb @@ -0,0 +1,14 @@ +class OrgResource < Avo::BaseResource + self.title = :id + self.includes = [] + # self.search_query = -> do + # scope.ransack(id_eq: params[:q], m: "or").result(distinct: false) + # end + + field :id, as: :id + # Fields generated from the model + field :handle, as: :text + field :full_name, as: :text + field :deleted_at, as: :date_time + # add fields here +end diff --git a/app/controllers/avo/orgs_controller.rb b/app/controllers/avo/orgs_controller.rb new file mode 100644 index 00000000000..a609597f52a --- /dev/null +++ b/app/controllers/avo/orgs_controller.rb @@ -0,0 +1,4 @@ +# This controller has been generated to enable Rails' resource routes. +# More information on https://docs.avohq.io/2.0/controllers.html +class Avo::OrgsController < Avo::ResourcesController +end diff --git a/app/models/org.rb b/app/models/org.rb new file mode 100644 index 00000000000..92f75444aa6 --- /dev/null +++ b/app/models/org.rb @@ -0,0 +1,2 @@ +class Org < ApplicationRecord +end diff --git a/db/migrate/20240630025625_create_orgs.rb b/db/migrate/20240630025625_create_orgs.rb new file mode 100644 index 00000000000..3f5b93135bd --- /dev/null +++ b/db/migrate/20240630025625_create_orgs.rb @@ -0,0 +1,11 @@ +class CreateOrgs < ActiveRecord::Migration[7.1] + def change + create_table :orgs do |t| + t.string :handle + t.string :full_name + t.timestamp :deleted_at + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index e1bf4f13690..be83009c562 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -382,6 +382,14 @@ t.index ["repository_owner", "repository_name", "repository_owner_id", "workflow_filename", "environment"], name: "index_oidc_trusted_publisher_github_actions_claims", unique: true end + create_table "orgs", force: :cascade do |t| + t.string "handle" + t.string "full_name" + t.datetime "deleted_at", precision: nil + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "ownership_calls", force: :cascade do |t| t.bigint "rubygem_id" t.bigint "user_id" diff --git a/test/factories/orgs.rb b/test/factories/orgs.rb new file mode 100644 index 00000000000..abb7aedde62 --- /dev/null +++ b/test/factories/orgs.rb @@ -0,0 +1,7 @@ +FactoryBot.define do + factory :org do + handle { "MyString" } + full_name { "MyString" } + deleted_at { "2024-06-29 19:56:25" } + end +end diff --git a/test/models/org_test.rb b/test/models/org_test.rb new file mode 100644 index 00000000000..54d5346c0bd --- /dev/null +++ b/test/models/org_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class OrgTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end From df107ce9b1a2e7313e14c6ba3dbb8a56700b7b7e Mon Sep 17 00:00:00 2001 From: Andre Arko Date: Sat, 29 Jun 2024 20:03:11 -0700 Subject: [PATCH 017/381] generate org memberships --- app/avo/resources/membership_resource.rb | 13 +++++++++++++ app/controllers/avo/memberships_controller.rb | 4 ++++ app/models/membership.rb | 4 ++++ db/migrate/20240630025804_create_memberships.rb | 10 ++++++++++ db/schema.rb | 13 ++++++++++++- test/factories/memberships.rb | 6 ++++++ test/models/membership_test.rb | 7 +++++++ 7 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 app/avo/resources/membership_resource.rb create mode 100644 app/controllers/avo/memberships_controller.rb create mode 100644 app/models/membership.rb create mode 100644 db/migrate/20240630025804_create_memberships.rb create mode 100644 test/factories/memberships.rb create mode 100644 test/models/membership_test.rb diff --git a/app/avo/resources/membership_resource.rb b/app/avo/resources/membership_resource.rb new file mode 100644 index 00000000000..f3100530202 --- /dev/null +++ b/app/avo/resources/membership_resource.rb @@ -0,0 +1,13 @@ +class MembershipResource < Avo::BaseResource + self.title = :id + self.includes = [] + # self.search_query = -> do + # scope.ransack(id_eq: params[:q], m: "or").result(distinct: false) + # end + + field :id, as: :id + # Fields generated from the model + field :user, as: :text + field :org, as: :text + # add fields here +end diff --git a/app/controllers/avo/memberships_controller.rb b/app/controllers/avo/memberships_controller.rb new file mode 100644 index 00000000000..679726950fa --- /dev/null +++ b/app/controllers/avo/memberships_controller.rb @@ -0,0 +1,4 @@ +# This controller has been generated to enable Rails' resource routes. +# More information on https://docs.avohq.io/2.0/controllers.html +class Avo::MembershipsController < Avo::ResourcesController +end diff --git a/app/models/membership.rb b/app/models/membership.rb new file mode 100644 index 00000000000..fda37390c4c --- /dev/null +++ b/app/models/membership.rb @@ -0,0 +1,4 @@ +class Membership < ApplicationRecord + belongs_to :user + belongs_to :org +end diff --git a/db/migrate/20240630025804_create_memberships.rb b/db/migrate/20240630025804_create_memberships.rb new file mode 100644 index 00000000000..3b6ccbf88c1 --- /dev/null +++ b/db/migrate/20240630025804_create_memberships.rb @@ -0,0 +1,10 @@ +class CreateMemberships < ActiveRecord::Migration[7.1] + def change + create_table :memberships do |t| + t.belongs_to :user, null: false, foreign_key: true + t.belongs_to :org, null: false, foreign_key: true + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index be83009c562..72b77cc2ba6 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_05_22_185717) do +ActiveRecord::Schema[7.1].define(version: 2024_06_30_025804) do # These are extensions that must be enabled in order to support this database enable_extension "hstore" enable_extension "pgcrypto" @@ -315,6 +315,15 @@ t.index ["task_name", "status", "created_at"], name: "index_maintenance_tasks_runs", order: { created_at: :desc } end + create_table "memberships", force: :cascade do |t| + t.bigint "user_id", null: false + t.bigint "org_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["org_id"], name: "index_memberships_on_org_id" + t.index ["user_id"], name: "index_memberships_on_user_id" + end + create_table "oidc_api_key_roles", force: :cascade do |t| t.bigint "oidc_provider_id", null: false t.bigint "user_id", null: false @@ -597,6 +606,8 @@ add_foreign_key "events_user_events", "users" add_foreign_key "ip_addresses", "geoip_infos" add_foreign_key "linksets", "rubygems", name: "linksets_rubygem_id_fk" + add_foreign_key "memberships", "orgs" + add_foreign_key "memberships", "users" add_foreign_key "oidc_api_key_roles", "oidc_providers" add_foreign_key "oidc_api_key_roles", "users" add_foreign_key "oidc_id_tokens", "api_keys" diff --git a/test/factories/memberships.rb b/test/factories/memberships.rb new file mode 100644 index 00000000000..103ea2939d2 --- /dev/null +++ b/test/factories/memberships.rb @@ -0,0 +1,6 @@ +FactoryBot.define do + factory :membership do + user { nil } + org { nil } + end +end diff --git a/test/models/membership_test.rb b/test/models/membership_test.rb new file mode 100644 index 00000000000..8506331ed1f --- /dev/null +++ b/test/models/membership_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class MembershipTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end From 81ea9ed1e375754dbb994140f8e827904eb27291 Mon Sep 17 00:00:00 2001 From: Andre Arko Date: Sat, 29 Jun 2024 20:58:55 -0700 Subject: [PATCH 018/381] change org full_name to just name --- db/migrate/20240630025625_create_orgs.rb | 2 +- db/schema.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/db/migrate/20240630025625_create_orgs.rb b/db/migrate/20240630025625_create_orgs.rb index 3f5b93135bd..3df9ac24df0 100644 --- a/db/migrate/20240630025625_create_orgs.rb +++ b/db/migrate/20240630025625_create_orgs.rb @@ -2,7 +2,7 @@ class CreateOrgs < ActiveRecord::Migration[7.1] def change create_table :orgs do |t| t.string :handle - t.string :full_name + t.string :name t.timestamp :deleted_at t.timestamps diff --git a/db/schema.rb b/db/schema.rb index 72b77cc2ba6..9c497e7c228 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -393,7 +393,7 @@ create_table "orgs", force: :cascade do |t| t.string "handle" - t.string "full_name" + t.string "name" t.datetime "deleted_at", precision: nil t.datetime "created_at", null: false t.datetime "updated_at", null: false From 9a0eefa44774e1aba1649a2725a5b743b979d072 Mon Sep 17 00:00:00 2001 From: Andre Arko Date: Sat, 29 Jun 2024 20:59:59 -0700 Subject: [PATCH 019/381] add membership confirmed_at --- db/migrate/20240630025804_create_memberships.rb | 1 + db/schema.rb | 1 + 2 files changed, 2 insertions(+) diff --git a/db/migrate/20240630025804_create_memberships.rb b/db/migrate/20240630025804_create_memberships.rb index 3b6ccbf88c1..88a844a0f9f 100644 --- a/db/migrate/20240630025804_create_memberships.rb +++ b/db/migrate/20240630025804_create_memberships.rb @@ -3,6 +3,7 @@ def change create_table :memberships do |t| t.belongs_to :user, null: false, foreign_key: true t.belongs_to :org, null: false, foreign_key: true + t.timestamp :confirmed_at, default: nil t.timestamps end diff --git a/db/schema.rb b/db/schema.rb index 9c497e7c228..2564d7773e8 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -318,6 +318,7 @@ create_table "memberships", force: :cascade do |t| t.bigint "user_id", null: false t.bigint "org_id", null: false + t.datetime "confirmed_at", precision: nil t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["org_id"], name: "index_memberships_on_org_id" From 51bb0e139cbcc2afb30700900795fda848cb1e56 Mon Sep 17 00:00:00 2001 From: Andre Arko Date: Sat, 29 Jun 2024 21:22:38 -0700 Subject: [PATCH 020/381] set up org relationships --- app/models/org.rb | 4 ++++ test/models/org_test.rb | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/models/org.rb b/app/models/org.rb index 92f75444aa6..15e362a4873 100644 --- a/app/models/org.rb +++ b/app/models/org.rb @@ -1,2 +1,6 @@ class Org < ApplicationRecord + has_many :rubygems, through: :ownerships + has_many :memberships, -> { where.not(confirmed_at: nil) }, dependent: :destroy, inverse_of: :org + has_many :unconfirmed_memberships, -> { where(confirmed_at: nil) }, class_name: "Membership", dependent: :destroy, inverse_of: :org + has_many :users, through: :memberships end diff --git a/test/models/org_test.rb b/test/models/org_test.rb index 54d5346c0bd..580fc1478a2 100644 --- a/test/models/org_test.rb +++ b/test/models/org_test.rb @@ -1,7 +1,7 @@ require "test_helper" class OrgTest < ActiveSupport::TestCase - # test "the truth" do - # assert true - # end + should have_many(:memberships).dependent(:destroy) + should have_many(:unconfirmed_memberships).dependent(:destroy) + should have_many(:users).through(:memberships) end From 839d53998453fc75a8757f8389404d786bcadb8d Mon Sep 17 00:00:00 2001 From: Andre Arko Date: Tue, 2 Jul 2024 16:24:07 -0700 Subject: [PATCH 021/381] create avo policies --- app/policies/admin/membership_policy.rb | 11 +++++++++++ app/policies/admin/org_policy.rb | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 app/policies/admin/membership_policy.rb create mode 100644 app/policies/admin/org_policy.rb diff --git a/app/policies/admin/membership_policy.rb b/app/policies/admin/membership_policy.rb new file mode 100644 index 00000000000..eb22ee86781 --- /dev/null +++ b/app/policies/admin/membership_policy.rb @@ -0,0 +1,11 @@ +class Admin::MembershipPolicy < Admin::ApplicationPolicy + class Scope < Admin::ApplicationPolicy::Scope + def resolve + scope.all + end + end + + def avo_show? + rubygems_org_admin? + end +end diff --git a/app/policies/admin/org_policy.rb b/app/policies/admin/org_policy.rb new file mode 100644 index 00000000000..94ef4d56e9d --- /dev/null +++ b/app/policies/admin/org_policy.rb @@ -0,0 +1,19 @@ +class Admin::OrgPolicy < Admin::ApplicationPolicy + class Scope < Admin::ApplicationPolicy::Scope + def resolve + scope.all + end + end + + def avo_index? + rubygems_org_admin? + end + + def avo_show? + rubygems_org_admin? + end + + def act_on? + rubygems_org_admin? + end +end From 2fdc8a071857fb76d3b5f1cebf1e92802c6b18b6 Mon Sep 17 00:00:00 2001 From: Andre Arko Date: Tue, 2 Jul 2024 16:24:49 -0700 Subject: [PATCH 022/381] membership test --- test/models/membership_test.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/models/membership_test.rb b/test/models/membership_test.rb index 8506331ed1f..27f5e5e3339 100644 --- a/test/models/membership_test.rb +++ b/test/models/membership_test.rb @@ -1,7 +1,6 @@ require "test_helper" class MembershipTest < ActiveSupport::TestCase - # test "the truth" do - # assert true - # end + should belong_to(:org) + should belong_to(:user) end From b42fd5bf3fa128c535ba6d1f2acbbbd7ba54353f Mon Sep 17 00:00:00 2001 From: Andre Arko Date: Tue, 2 Jul 2024 16:40:58 -0700 Subject: [PATCH 023/381] add and test membership confirmation --- app/models/membership.rb | 6 ++++++ test/models/membership_test.rb | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/app/models/membership.rb b/app/models/membership.rb index fda37390c4c..14185fd6f87 100644 --- a/app/models/membership.rb +++ b/app/models/membership.rb @@ -1,4 +1,10 @@ class Membership < ApplicationRecord belongs_to :user belongs_to :org + + scope :confirmed, -> { where.not(confirmed_at: nil) } + + def confirmed? + !confirmed_at.nil? + end end diff --git a/test/models/membership_test.rb b/test/models/membership_test.rb index 27f5e5e3339..28578716518 100644 --- a/test/models/membership_test.rb +++ b/test/models/membership_test.rb @@ -3,4 +3,23 @@ class MembershipTest < ActiveSupport::TestCase should belong_to(:org) should belong_to(:user) + + setup do + @org = FactoryBot.create(:org) + @user = FactoryBot.create(:user) + end + + should "be unconfirmed by default" do + membership = Membership.create!(org: @org, user: @user) + + assert_not(membership.confirmed?) + assert_empty(Membership.confirmed) + end + + should "be confirmed with confirmed_at" do + membership = Membership.create!(org: @org, user: @user, confirmed_at: Time.zone.now) + + assert_predicate(membership, :confirmed?) + assert_equal(Membership.confirmed, [membership]) + end end From 9d0e5aeb127de6191ffa442ca983aad52de95289 Mon Sep 17 00:00:00 2001 From: Andre Arko Date: Tue, 2 Jul 2024 17:12:14 -0700 Subject: [PATCH 024/381] fix membership and org factories --- test/factories/memberships.rb | 4 ++-- test/factories/orgs.rb | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/factories/memberships.rb b/test/factories/memberships.rb index 103ea2939d2..7b619b4e34b 100644 --- a/test/factories/memberships.rb +++ b/test/factories/memberships.rb @@ -1,6 +1,6 @@ FactoryBot.define do factory :membership do - user { nil } - org { nil } + user + org end end diff --git a/test/factories/orgs.rb b/test/factories/orgs.rb index abb7aedde62..1b88c7e9b60 100644 --- a/test/factories/orgs.rb +++ b/test/factories/orgs.rb @@ -1,7 +1,7 @@ FactoryBot.define do factory :org do - handle { "MyString" } - full_name { "MyString" } - deleted_at { "2024-06-29 19:56:25" } + handle { |i| "org_#{i}" } + name { |i| "Organization #{i}" } + deleted_at { nil } end end From 2d56dea13859ffa1123fc1a0c805bc4f433262b1 Mon Sep 17 00:00:00 2001 From: Andre Arko Date: Tue, 2 Jul 2024 17:13:41 -0700 Subject: [PATCH 025/381] add org validations --- app/models/org.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/models/org.rb b/app/models/org.rb index 15e362a4873..594c76ec6d1 100644 --- a/app/models/org.rb +++ b/app/models/org.rb @@ -1,4 +1,12 @@ class Org < ApplicationRecord + validates :handle, presence: true, uniqueness: true + validates :name, presence: true + validate :unique_with_user_handle + + def unique_with_user_handle + errors.add(:handle, "is not available") if User.exists?(handle: handle) + end + has_many :rubygems, through: :ownerships has_many :memberships, -> { where.not(confirmed_at: nil) }, dependent: :destroy, inverse_of: :org has_many :unconfirmed_memberships, -> { where(confirmed_at: nil) }, class_name: "Membership", dependent: :destroy, inverse_of: :org From 0629e55bea9af80a15e28313ef777f62ec8e610c Mon Sep 17 00:00:00 2001 From: Andre Arko Date: Tue, 2 Jul 2024 17:27:10 -0700 Subject: [PATCH 026/381] refine and test validations --- app/models/org.rb | 10 ++++-- test/models/org_test.rb | 67 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 3 deletions(-) diff --git a/app/models/org.rb b/app/models/org.rb index 594c76ec6d1..94e0418059c 100644 --- a/app/models/org.rb +++ b/app/models/org.rb @@ -1,10 +1,14 @@ class Org < ApplicationRecord - validates :handle, presence: true, uniqueness: true - validates :name, presence: true + validates :handle, presence: true, uniqueness: { case_sensitive: false }, length: { within: 2..40 } + validates :handle, format: { + with: /\A[A-Za-z][A-Za-z_\-0-9]*\z/, + message: "must start with a letter and can only contain letters, numbers, underscores, and dashes" + }, allow_nil: true + validates :name, presence: true, length: { within: 2..255 } validate :unique_with_user_handle def unique_with_user_handle - errors.add(:handle, "is not available") if User.exists?(handle: handle) + errors.add(:handle, "has already been taken") if handle && User.where("handle = lower(?)", handle.downcase).any? end has_many :rubygems, through: :ownerships diff --git a/test/models/org_test.rb b/test/models/org_test.rb index 580fc1478a2..5ea3301f364 100644 --- a/test/models/org_test.rb +++ b/test/models/org_test.rb @@ -4,4 +4,71 @@ class OrgTest < ActiveSupport::TestCase should have_many(:memberships).dependent(:destroy) should have_many(:unconfirmed_memberships).dependent(:destroy) should have_many(:users).through(:memberships) + + # Waiting for Ownerships to be made polymorphic + # + # should have_many(:ownerships).dependent(:destroy) + # should have_many(:unconfirmed_ownerships).dependent(:destroy) + # should have_many(:rubygems).through(:ownerships) + + context "validations" do + context "handle" do + should allow_value("CapsLOCK").for(:handle) + should_not allow_value(nil).for(:handle) + should_not allow_value("1abcde").for(:handle) + should_not allow_value("abc^%def").for(:handle) + should_not allow_value("abc\n