From 70092ccffd6a34a12c3ef273823e3c85c804fe0f Mon Sep 17 00:00:00 2001 From: Rinse Vlaswinkel <43185712+RinseV@users.noreply.github.com> Date: Thu, 5 Nov 2026 10:35:26 +0100 Subject: [PATCH 1/9] test: Configure cache store inside combustion initializer combustion 1.7.0 only loads its Rails application inside Combustion.initialize!, so Rails.application is nil before that call. This broke the whole spec suite in CI. --- spec/spec_helper.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6e06149..d49bdce 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -7,10 +7,10 @@ Bundler.require(*Rails.groups) -Rails.application.config.cache_store = :null_store - # Load the parts from rails we need with combustion -Combustion.initialize! :active_record, :action_controller +Combustion.initialize! :active_record, :action_controller do + config.cache_store = :null_store +end require 'rspec/rails' From e9037a25d8333e670e59d88f2e05334eafb8d895 Mon Sep 17 00:00:00 2001 From: Rinse Vlaswinkel <43185712+RinseV@users.noreply.github.com> Date: Thu, 5 Nov 2026 10:35:27 +0100 Subject: [PATCH 2/9] build: Pin json gem to < 3.0 json 3.0 contains breaking changes. Same pin as in drieam-oauth2. --- keypairs.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/keypairs.gemspec b/keypairs.gemspec index b3ba7b3..e6bfb8c 100644 --- a/keypairs.gemspec +++ b/keypairs.gemspec @@ -27,6 +27,7 @@ Gem::Specification.new do |spec| spec.add_dependency 'actionpack', '>= 7.1', '< 9' # Depend on actionpack to share public keys spec.add_dependency 'activerecord', '>= 7.1', '< 9' # Depend on activerecord as ORM + spec.add_dependency 'json', '< 3.0' # json 3.0 has breaking changes spec.add_dependency 'jwt', '>= 2.5', '< 4' # Working with JSON Web Tokens spec.add_dependency 'lockbox', '>= 1.3', '< 3.0' # Encrypt and decrypt attributes From fd3464e6ef3505ce00ce3f46aacecc2eb4221645 Mon Sep 17 00:00:00 2001 From: Rinse Vlaswinkel <43185712+RinseV@users.noreply.github.com> Date: Thu, 5 Nov 2026 10:35:34 +0100 Subject: [PATCH 3/9] build!: Drop support for Ruby 3.2 and Rails 7.1/7.2 Align the supported versions with drieam-oauth2: - Require Ruby >= 3.3 and actionpack/activerecord >= 8.0, < 9 - Test Ruby 3.3, 3.4 and 4.0 against Rails 8.0 and 8.1 - Regenerate the Appraisals and gemfiles for Rails 8.0 and 8.1 - Use actions/checkout v7 in CI BREAKING CHANGE: Ruby 3.2 and Rails 7.1/7.2 are no longer supported. --- .github/workflows/ci.yml | 11 +++++------ .rubocop.yml | 2 +- Appraisals | 12 ++++-------- gemfiles/rails_7_2.gemfile | 7 ------- gemfiles/rails_8_0.gemfile | 2 +- gemfiles/{rails_7_1.gemfile => rails_8_1.gemfile} | 2 +- keypairs.gemspec | 6 +++--- 7 files changed, 15 insertions(+), 27 deletions(-) delete mode 100644 gemfiles/rails_7_2.gemfile rename gemfiles/{rails_7_1.gemfile => rails_8_1.gemfile} (74%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1bc84b0..9baeb4e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,7 +6,7 @@ jobs: steps: - name: Check out code - uses: actions/checkout@v4 + uses: actions/checkout@v7 - uses: ruby/setup-ruby@v1 with: @@ -21,7 +21,7 @@ jobs: steps: - name: Check out code - uses: actions/checkout@v4 + uses: actions/checkout@v7 - uses: ruby/setup-ruby@v1 with: @@ -36,17 +36,16 @@ jobs: fail-fast: false matrix: ruby: - - '3.2' - '3.3' - '3.4' + - '4.0' gemfile: - - rails_7_1 - - rails_7_2 - rails_8_0 + - rails_8_1 runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Set BUNDLE_GEMFILE run: echo 'BUNDLE_GEMFILE=${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile' >> $GITHUB_ENV diff --git a/.rubocop.yml b/.rubocop.yml index ac548ea..04f14f4 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -3,7 +3,7 @@ require: - rubocop-rails # Rails-specific analysis AllCops: - TargetRubyVersion: 3.2 + TargetRubyVersion: 3.3 NewCops: enable Exclude: - 'gemfiles/*' diff --git a/Appraisals b/Appraisals index 5d275a7..22f81ff 100644 --- a/Appraisals +++ b/Appraisals @@ -1,13 +1,9 @@ # frozen_string_literal: true -appraise 'rails-6-1' do - gem 'rails', '~> 6.1.0' +appraise 'rails-8-0' do + gem 'rails', '>= 8.0', '< 8.1' end -appraise 'rails-7-0' do - gem 'rails', '~> 7.0.0' -end - -appraise 'rails-7-1' do - gem 'rails', '~> 7.1.0' +appraise 'rails-8-1' do + gem 'rails', '>= 8.1', '< 8.2' end diff --git a/gemfiles/rails_7_2.gemfile b/gemfiles/rails_7_2.gemfile deleted file mode 100644 index 92cc2b2..0000000 --- a/gemfiles/rails_7_2.gemfile +++ /dev/null @@ -1,7 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "rails", "~> 7.2.0" - -gemspec path: "../" diff --git a/gemfiles/rails_8_0.gemfile b/gemfiles/rails_8_0.gemfile index 3b3765b..3100613 100644 --- a/gemfiles/rails_8_0.gemfile +++ b/gemfiles/rails_8_0.gemfile @@ -2,6 +2,6 @@ source "https://rubygems.org" -gem "rails", "~> 8.0.0" +gem "rails", ">= 8.0", "< 8.1" gemspec path: "../" diff --git a/gemfiles/rails_7_1.gemfile b/gemfiles/rails_8_1.gemfile similarity index 74% rename from gemfiles/rails_7_1.gemfile rename to gemfiles/rails_8_1.gemfile index 35a0ba3..434ad83 100644 --- a/gemfiles/rails_7_1.gemfile +++ b/gemfiles/rails_8_1.gemfile @@ -2,6 +2,6 @@ source "https://rubygems.org" -gem "rails", "~> 7.1.0" +gem "rails", ">= 8.1", "< 8.2" gemspec path: "../" diff --git a/keypairs.gemspec b/keypairs.gemspec index e6bfb8c..4684547 100644 --- a/keypairs.gemspec +++ b/keypairs.gemspec @@ -18,15 +18,15 @@ Gem::Specification.new do |spec| spec.description = spec.summary spec.license = 'MIT' - spec.required_ruby_version = '>= 3.2' + spec.required_ruby_version = '>= 3.3' spec.metadata['homepage_uri'] = spec.homepage spec.metadata['source_code_uri'] = 'https://github.com/Drieam/keypairs' spec.files = Dir['{app,db,lib}/**/*', 'LICENSE', 'README.md'] - spec.add_dependency 'actionpack', '>= 7.1', '< 9' # Depend on actionpack to share public keys - spec.add_dependency 'activerecord', '>= 7.1', '< 9' # Depend on activerecord as ORM + spec.add_dependency 'actionpack', '>= 8.0', '< 9' # Depend on actionpack to share public keys + spec.add_dependency 'activerecord', '>= 8.0', '< 9' # Depend on activerecord as ORM spec.add_dependency 'json', '< 3.0' # json 3.0 has breaking changes spec.add_dependency 'jwt', '>= 2.5', '< 4' # Working with JSON Web Tokens spec.add_dependency 'lockbox', '>= 1.3', '< 3.0' # Encrypt and decrypt attributes From bc891aed089f8de540f98bf44f76eb53d8c7091c Mon Sep 17 00:00:00 2001 From: Rinse Vlaswinkel <43185712+RinseV@users.noreply.github.com> Date: Thu, 5 Nov 2026 10:35:43 +0100 Subject: [PATCH 4/9] ci: Switch to release-please for version updates Same setup as drieam-oauth2. release-please opens a versioning PR after each merge to main and publishes the gem to RubyGems and the GitHub package registry once that PR is merged. The version file now holds the real version (2.0.1, the latest release). --- .github/workflows/publish.yml | 69 ++++++++++++++++------------------- .release-please-manifest.json | 1 + README.md | 5 ++- lib/keypairs/version.rb | 2 +- release-please-config.json | 9 +++++ 5 files changed, 47 insertions(+), 39 deletions(-) create mode 100644 .release-please-manifest.json create mode 100644 release-please-config.json diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 1eb86dc..3f696bd 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,58 +1,53 @@ name: Publish + on: - release: - types: [published] + push: + branches: + - main + +permissions: + contents: write + packages: write + pull-requests: write jobs: - publish-github: + publish: runs-on: ubuntu-latest steps: - - name: Checkout repo - uses: actions/checkout@v2 + - uses: googleapis/release-please-action@v5.0.0 + id: release + with: + config-file: release-please-config.json + manifest-file: .release-please-manifest.json + + - name: Checkout code + if: ${{ steps.release.outputs.releases_created == 'true' }} + uses: actions/checkout@v7.0.1 - name: Setup Ruby - uses: ruby/setup-ruby@v1 + if: ${{ steps.release.outputs.releases_created == 'true' }} + uses: ruby/setup-ruby@v1.336.0 with: - ruby-version: 3.0 + ruby-version: '3.4' + bundler-cache: true - - name: Setup GitHub Package Registry credentials + - name: Build and publish gem to registry + if: ${{ steps.release.outputs.releases_created == 'true' }} run: | + gem install bundler + bundle config unset deployment + bundle install mkdir -p $HOME/.gem touch $HOME/.gem/credentials chmod 0600 $HOME/.gem/credentials printf -- "---\n:github: Bearer ${{ secrets.GITHUB_TOKEN }}\n" > $HOME/.gem/credentials - - - name: Replace version by tag value - run: sed -i "s/'[0-9]\.[0-9]\..*'/'${GITHUB_REF##*/}'/" lib/keypairs/version.rb - - - name: Build and Publish gem to GitHub Package Registry - run: | gem build --verbose *.gemspec gem push --verbose --key github --host https://rubygems.pkg.github.com/${OWNER} *.gem env: OWNER: Drieam - publish-rubygems: - runs-on: ubuntu-latest - steps: - - name: Checkout repo - uses: actions/checkout@v2 - - - name: Setup Ruby - uses: ruby/setup-ruby@v1 - with: - ruby-version: 3.0 - - - name: Replace version by tag value - run: sed -i "s/'[0-9]\.[0-9]\..*'/'${GITHUB_REF##*/}'/" lib/keypairs/version.rb - - - name: Publish to RubyGems - run: | - mkdir -p $HOME/.gem - touch $HOME/.gem/credentials - chmod 0600 $HOME/.gem/credentials - printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials - gem build --verbose *.gemspec - gem push --verbose *.gem + - name: Publish gem to RubyGems + if: ${{ steps.release.outputs.releases_created == 'true' }} + run: gem push --verbose *.gem env: - GEM_HOST_API_KEY: ${{secrets.RUBYGEMS_AUTH_TOKEN}} + GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_AUTH_TOKEN }} diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..ed49281 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1 @@ +{".":"2.0.1"} diff --git a/README.md b/README.md index a9a5557..4ab441a 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,10 @@ get :jwks, to: Keypairs::PublicKeysController.action(:index) ``` ## Releasing new version -Publishing a new version is handled by the publish workflow. This workflow publishes a GitHub release to rubygems and GitHub package registry with the version defined in the release. +Publishing a new version is handled by [release-please](https://github.com/googleapis/release-please). Whenever a PR is +merged, release-please will create/update a versioning PR. Once this versioning PR is approved and merged, a new version +of the gem will automatically be published to RubyGems and the GitHub package registry. The changelog will be updated +automatically. ## Contributing Bug reports and pull requests are welcome on GitHub at https://github.com/Drieam/keypairs. diff --git a/lib/keypairs/version.rb b/lib/keypairs/version.rb index d354a9b..0083b24 100644 --- a/lib/keypairs/version.rb +++ b/lib/keypairs/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Keypairs - VERSION = '1.3.4.develop' + VERSION = '2.0.1' end diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 0000000..0bffd29 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,9 @@ +{ + "packages": { + ".": { + "release-type": "ruby", + "version-file": "lib/keypairs/version.rb", + "include-v-in-tag": false + } + } +} From 0c34ec3acc136654b45e499278e7e58b4e004c5d Mon Sep 17 00:00:00 2001 From: Rinse Vlaswinkel <43185712+RinseV@users.noreply.github.com> Date: Thu, 5 Nov 2026 10:35:43 +0100 Subject: [PATCH 5/9] ci: Run CI on pull requests and annotate lint results Run on pushes to main and on pull requests, so PRs from forks are checked as well. Use the github output format for rubocop and brakeman so offenses show up inline on the PR, and run the linters on Ruby 3.4. --- .github/workflows/ci.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9baeb4e..ce75a46 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,11 @@ name: CI -on: [push] + +on: + push: + branches: + - main + pull_request: + jobs: rubocop: runs-on: ubuntu-latest @@ -10,11 +16,11 @@ jobs: - uses: ruby/setup-ruby@v1 with: - ruby-version: 3.3 + ruby-version: '3.4' bundler-cache: true - name: Run rubocop - run: bundle exec rubocop + run: bundle exec rubocop --format github brakeman: runs-on: ubuntu-latest @@ -25,11 +31,11 @@ jobs: - uses: ruby/setup-ruby@v1 with: - ruby-version: 3.3 + ruby-version: '3.4' bundler-cache: true - name: Run brakeman - run: bundle exec brakeman --quiet --format tabs --force-scan + run: bundle exec brakeman --quiet --format github --force-scan rspec: strategy: From 25f1ebf4e56f1bfe76237a3b788b84c2da31a57c Mon Sep 17 00:00:00 2001 From: Rinse Vlaswinkel <43185712+RinseV@users.noreply.github.com> Date: Thu, 5 Nov 2026 10:35:44 +0100 Subject: [PATCH 6/9] chore: Load rubocop extensions as plugins Recent versions of rubocop-rails and rubocop-performance deprecate loading them through require. --- .rubocop.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.rubocop.yml b/.rubocop.yml index 04f14f4..ec9dbd1 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,4 +1,4 @@ -require: +plugins: - rubocop-performance # Performance optimization analysis - rubocop-rails # Rails-specific analysis From f87b57e92fd8c612d30ab117b5879545f566b2bb Mon Sep 17 00:00:00 2001 From: Rinse Vlaswinkel <43185712+RinseV@users.noreply.github.com> Date: Thu, 5 Nov 2026 10:35:44 +0100 Subject: [PATCH 7/9] chore: Stop tracking sqlite WAL files of the test database The -shm and -wal files are created and removed by every spec run, which leaves the working tree dirty. --- .gitignore | 1 + spec/internal/db/keypairs_test.sqlite3-shm | Bin 32768 -> 0 bytes spec/internal/db/keypairs_test.sqlite3-wal | Bin 16512 -> 0 bytes 3 files changed, 1 insertion(+) delete mode 100644 spec/internal/db/keypairs_test.sqlite3-shm delete mode 100644 spec/internal/db/keypairs_test.sqlite3-wal diff --git a/.gitignore b/.gitignore index 3358b34..5c5db6d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ log/*.log pkg/ spec/internal/db/*.sqlite3 +spec/internal/db/*.sqlite3-* spec/internal/log/*.log spec/internal/storage/ diff --git a/spec/internal/db/keypairs_test.sqlite3-shm b/spec/internal/db/keypairs_test.sqlite3-shm deleted file mode 100644 index 75609407622ba18fa71cff44a4c951f02be22686..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 zcmeI)y9ok85C-7$fsf4aumv%*3nK$TF0l?PFxJG(z!n6{F}Nl)(^-+j)KK^PVc20= zcG<6hDeGyG(vE5s#i$$WFzS3<%4k*bHZtEFJM#`#p_*9d3piS8+_js_!)t02q1s}0tg_000Iag zfB*sr1XLjGpW@C5GHx1kUM-YDpRE5|GAb Date: Thu, 5 Nov 2026 10:37:12 +0100 Subject: [PATCH 8/9] ci: Generate workflow lockfile Generated with gh actions-lock. Pins every action to a verified commit, as done in drieam-oauth2. Supersedes #26. Tracked in Drieam/SecDevOps#661 --- .github/workflows/actions.lock | 28 ++++++++++++++++++++++++++++ .github/workflows/ci.yml | 12 ++++++------ 2 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/actions.lock diff --git a/.github/workflows/actions.lock b/.github/workflows/actions.lock new file mode 100644 index 0000000..5e58a87 --- /dev/null +++ b/.github/workflows/actions.lock @@ -0,0 +1,28 @@ +# This file is machine-generated by `gh actions-lock`. +# Do not edit by hand; run `gh actions-lock` to update. +# Docs: https://gh.io/actions-lockfile +version: 'v0.0.3' +workflows: + '.github/workflows/ci.yml': + - 'actions/checkout@v7.0.1' + - 'ruby/setup-ruby@v1.336.0' + '.github/workflows/publish.yml': + - 'actions/checkout@v7.0.1' + - 'googleapis/release-please-action@v5.0.0' + - 'ruby/setup-ruby@v1.336.0' +dependencies: + 'actions/checkout@v7.0.1': + ref: 'v7.0.1' + commit: 'sha1-3d3c42e5aac5ba805825da76410c181273ba90b1' + owner_id: 44036562 + repo_id: 197814629 + 'googleapis/release-please-action@v5.0.0': + ref: 'v5.0.0' + commit: 'sha1-45996ed1f6d02564a971a2fa1b5860e934307cf7' + owner_id: 16785467 + repo_id: 262236530 + 'ruby/setup-ruby@v1.336.0': + ref: 'v1.336.0' + commit: 'sha1-de492cf36cbab201753d720ce4f4e336cd688c94' + owner_id: 210414 + repo_id: 231208785 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce75a46..df26a54 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,9 +12,9 @@ jobs: steps: - name: Check out code - uses: actions/checkout@v7 + uses: actions/checkout@v7.0.1 - - uses: ruby/setup-ruby@v1 + - uses: ruby/setup-ruby@v1.336.0 with: ruby-version: '3.4' bundler-cache: true @@ -27,9 +27,9 @@ jobs: steps: - name: Check out code - uses: actions/checkout@v7 + uses: actions/checkout@v7.0.1 - - uses: ruby/setup-ruby@v1 + - uses: ruby/setup-ruby@v1.336.0 with: ruby-version: '3.4' bundler-cache: true @@ -51,12 +51,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v7 + uses: actions/checkout@v7.0.1 - name: Set BUNDLE_GEMFILE run: echo 'BUNDLE_GEMFILE=${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile' >> $GITHUB_ENV - - uses: ruby/setup-ruby@v1 + - uses: ruby/setup-ruby@v1.336.0 with: ruby-version: ${{ matrix.ruby }} bundler-cache: true From 45597096da3309590e7f11b4e6954c8174457956 Mon Sep 17 00:00:00 2001 From: Rinse Vlaswinkel <43185712+RinseV@users.noreply.github.com> Date: Thu, 5 Nov 2026 10:42:24 +0100 Subject: [PATCH 9/9] ci: Publish from the release SHA in separately retryable jobs Check out the commit release-please tagged instead of the triggering commit, so the gem always matches its release tag. Publishing to GitHub Packages and RubyGems in their own jobs means a failed upload can be retried with "Re-run failed jobs", reusing the release outputs, without pushing the gem twice. --- .github/workflows/publish.yml | 44 +++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 3f696bd..aa717f0 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -11,8 +11,11 @@ permissions: pull-requests: write jobs: - publish: + release: runs-on: ubuntu-latest + outputs: + release_created: ${{ steps.release.outputs.release_created }} + sha: ${{ steps.release.outputs.sha }} steps: - uses: googleapis/release-please-action@v5.0.0 id: release @@ -20,23 +23,24 @@ jobs: config-file: release-please-config.json manifest-file: .release-please-manifest.json + # Separate jobs so a failed upload can be retried with "Re-run failed jobs" without publishing twice + publish-github: + needs: release + if: ${{ needs.release.outputs.release_created == 'true' }} + runs-on: ubuntu-latest + steps: - name: Checkout code - if: ${{ steps.release.outputs.releases_created == 'true' }} uses: actions/checkout@v7.0.1 + with: + ref: ${{ needs.release.outputs.sha }} - name: Setup Ruby - if: ${{ steps.release.outputs.releases_created == 'true' }} uses: ruby/setup-ruby@v1.336.0 with: ruby-version: '3.4' - bundler-cache: true - - name: Build and publish gem to registry - if: ${{ steps.release.outputs.releases_created == 'true' }} + - name: Build and publish gem to GitHub Package Registry run: | - gem install bundler - bundle config unset deployment - bundle install mkdir -p $HOME/.gem touch $HOME/.gem/credentials chmod 0600 $HOME/.gem/credentials @@ -46,8 +50,24 @@ jobs: env: OWNER: Drieam - - name: Publish gem to RubyGems - if: ${{ steps.release.outputs.releases_created == 'true' }} - run: gem push --verbose *.gem + publish-rubygems: + needs: release + if: ${{ needs.release.outputs.release_created == 'true' }} + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v7.0.1 + with: + ref: ${{ needs.release.outputs.sha }} + + - name: Setup Ruby + uses: ruby/setup-ruby@v1.336.0 + with: + ruby-version: '3.4' + + - name: Build and publish gem to RubyGems + run: | + gem build --verbose *.gemspec + gem push --verbose *.gem env: GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_AUTH_TOKEN }}