diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ed6c919..61a81a9 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -9,24 +9,17 @@ permissions:
jobs:
test:
- name: Ruby ${{ matrix.ruby }} / Rails ${{ matrix.rails }} / AA ${{ matrix.activeadmin }} / OOIDC ${{ matrix.omniauth_openid_connect }}
+ name: Ruby ${{ matrix.ruby }} / ${{ matrix.gemfile }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
ruby: ['3.2', '3.3', '3.4']
- rails: ['7.2.0', '8.0.0']
- activeadmin: ['3.5.0']
- # 0.6.x → openid_connect 1.x (httpclient, no faraday dep).
- # 0.7.x / 0.8.x → openid_connect 2.x (faraday 2.x).
- omniauth_openid_connect: ['0.6.0', '0.7.0', '0.8.0']
- # AA 3.4.0 is excluded: it pins devise < 5, which is
- # incompatible with the devise >= 4.9 floor this gem needs.
- # Support starts at ActiveAdmin 3.5, which lifted that cap.
+ gemfile:
+ - gemfiles/activeadmin_3.5.gemfile
+ - gemfiles/activeadmin_4.0.gemfile
env:
- RAILS: ${{ matrix.rails }}
- AA: ${{ matrix.activeadmin }}
- OOIDC: ${{ matrix.omniauth_openid_connect }}
+ BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
diff --git a/.gitignore b/.gitignore
index 970778d..34bd2a2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,11 +11,16 @@
.DS_Store
.rspec_status
/Gemfile.lock
+/gemfiles/*.lock
/spec/dummy/log/
/spec/dummy/tmp/
/spec/dummy/db/*.sqlite3
/spec/dummy/db/*.sqlite3-journal
/spec/dummy/storage/
+/spec/dummy_engine/log/
+/spec/dummy_engine/tmp/
+/spec/dummy_isolated/log/
+/spec/dummy_isolated/tmp/
# The dummy app's database.yml is checked in — override a global
# ignore rule that excludes "database.yml" everywhere by default.
diff --git a/Gemfile b/Gemfile
index 34184fc..b839084 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,19 +1,11 @@
# frozen_string_literal: true
-source "https://rubygems.org"
-
-gemspec
-
-default_rails_version = "7.2.0"
-default_activeadmin_version = "3.5.0"
-
-rails_version = ENV.fetch("RAILS", default_rails_version)
-activeadmin_version = ENV.fetch("AA", default_activeadmin_version)
-# 0.6.x uses openid_connect 1.x (httpclient, no faraday) — required for
-# host apps still on faraday 1.x. 0.7.x uses openid_connect 2.x (faraday 2.x).
-ooidc_version = ENV["OOIDC"]
-
-gem "rails", "~> #{rails_version}"
-gem "activerecord", "~> #{rails_version}"
-gem "activeadmin", "~> #{activeadmin_version}"
-gem "omniauth_openid_connect", "~> #{ooidc_version}" if ooidc_version
+# Local development and `rake spec:all` (run without BUNDLE_GEMFILE)
+# default to the ActiveAdmin 3.5 stack. CI selects a specific stack via
+# BUNDLE_GEMFILE — see gemfiles/activeadmin_3.5.gemfile (Sprockets/Sassc)
+# and gemfiles/activeadmin_4.0.gemfile (Propshaft/importmap/Tailwind).
+#
+# eval_gemfile keeps a single source of truth: the `gemspec path: ".."`
+# inside the eval'd file resolves relative to gemfiles/, i.e. this repo
+# root, exactly as it does when CI loads the gemfile directly.
+eval_gemfile File.expand_path("gemfiles/activeadmin_3.5.gemfile", __dir__)
diff --git a/activeadmin-oidc.gemspec b/activeadmin-oidc.gemspec
index 5921b54..c443dc1 100644
--- a/activeadmin-oidc.gemspec
+++ b/activeadmin-oidc.gemspec
@@ -27,7 +27,7 @@ Gem::Specification.new do |spec|
]
spec.require_paths = ["lib"]
- spec.add_dependency "activeadmin", ">= 3.5", "< 4"
+ spec.add_dependency "activeadmin", ">= 3.5", "< 5"
# Devise 5.0 wraps `Devise.mappings` with `reload_routes_unless_loaded`
# (heartcombo/devise#5728) so OmniAuth's failure handler works under
# Rails 8 lazy route loading without an engine-side workaround.
@@ -46,8 +46,11 @@ Gem::Specification.new do |spec|
spec.add_development_dependency "webmock", ">= 3.19"
spec.add_development_dependency "jwt", ">= 2.7"
spec.add_development_dependency "sqlite3", ">= 1.7"
- spec.add_development_dependency "sprockets-rails", ">= 3.4"
- spec.add_development_dependency "sassc-rails", ">= 2.1"
+ # The asset pipeline gems live in the per-version gemfiles under
+ # gemfiles/ rather than here: ActiveAdmin 3.5 needs Sprockets + Sassc,
+ # while ActiveAdmin 4.0 needs Propshaft + importmap + cssbundling +
+ # Tailwind. Keeping them out of the gemspec lets each gemfile install
+ # exactly one asset stack instead of both.
spec.add_development_dependency "rake", ">= 13.0"
spec.add_development_dependency "rubocop", ">= 1.60"
spec.add_development_dependency "rubocop-rails", ">= 2.20"
diff --git a/app/views/active_admin/devise/sessions/new.html.erb b/app/views/active_admin/devise/sessions/new.html.erb
index f87e671..7c49318 100644
--- a/app/views/active_admin/devise/sessions/new.html.erb
+++ b/app/views/active_admin/devise/sessions/new.html.erb
@@ -1,7 +1,24 @@
-
-
<%= active_admin_application.site_title(self) %>
+<% if ActiveAdmin::Oidc.aa_v4? %>
+
+
+ <%= site_title %> <%= set_page_title t('active_admin.devise.login.title') %>
+
- <%= form_tag omniauth_authorize_path(resource_name, :oidc), method: :post, data: { turbo: false } do %>
- <%= submit_tag ActiveAdmin::Oidc.config.login_button_label %>
- <% end %>
-
+ <%= button_to ActiveAdmin::Oidc.config.login_button_label,
+ "/admin/auth/oidc",
+ method: :post,
+ class: "activeadmin-oidc-login-button w-full",
+ form_class: 'formtastic',
+ data: { turbo: false } %>
+
+<% else %>
+
+
<%= active_admin_application.site_title(self) %>
+
+ <%= button_to ActiveAdmin::Oidc.config.login_button_label,
+ "/admin/auth/oidc",
+ method: :post,
+ class: "activeadmin-oidc-login-button",
+ data: { turbo: false } %>
+
+<% end %>
diff --git a/gemfiles/activeadmin_3.5.gemfile b/gemfiles/activeadmin_3.5.gemfile
new file mode 100644
index 0000000..a81b26f
--- /dev/null
+++ b/gemfiles/activeadmin_3.5.gemfile
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+source "https://rubygems.org"
+
+gemspec path: ".."
+
+# ActiveAdmin 3.5 line: classic Sprockets + Sassc asset pipeline.
+gem "activeadmin", "~> 3.5.0"
+gem "rails", "~> 7.2.0"
+
+# openid_connect 1.x line (httpclient-based, no faraday dep). Pinning the
+# 0.6.x series here keeps CI exercising the pre-faraday strategy path.
+gem "omniauth_openid_connect", "~> 0.6.0"
+
+gem "sprockets-rails", ">= 3.4"
+gem "sassc-rails", ">= 2.1"
diff --git a/gemfiles/activeadmin_4.0.gemfile b/gemfiles/activeadmin_4.0.gemfile
new file mode 100644
index 0000000..dc65df7
--- /dev/null
+++ b/gemfiles/activeadmin_4.0.gemfile
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+source "https://rubygems.org"
+
+gemspec path: ".."
+
+# ActiveAdmin 4.0 line (currently shipping as 4.0.0.beta*). AA 4 replaces
+# the Sprockets/Sassc pipeline with Propshaft + importmap + cssbundling +
+# Tailwind, so the asset gems differ entirely from the 3.5 gemfile.
+gem "activeadmin", ">= 4.0.0.beta", "< 5"
+gem "rails", "~> 8.0.0"
+
+# openid_connect 2.x line (faraday 2.x).
+gem "omniauth_openid_connect", "~> 0.8.0"
+
+gem "propshaft"
+gem "importmap-rails"
+gem "cssbundling-rails"
+gem "tailwindcss-rails", "~> 4.0"
diff --git a/lib/activeadmin-oidc.rb b/lib/activeadmin-oidc.rb
index 99f5cbd..dc6544b 100644
--- a/lib/activeadmin-oidc.rb
+++ b/lib/activeadmin-oidc.rb
@@ -3,6 +3,7 @@
require "logger"
require "active_support/core_ext/object/blank"
require "activeadmin/oidc/version"
+require "active_admin/version"
# `omniauth-rails_csrf_protection` registers a Railtie that replaces
# OmniAuth 2.x's Rack-level authenticity check with Rails' own forgery
@@ -53,6 +54,15 @@ def reset!
@logger = nil
end
+ # True when the installed ActiveAdmin is the 4.x line (including the
+ # 4.0.0 prereleases). AA 4 ships a Tailwind-based admin layout, so
+ # the login view override must emit Tailwind markup instead of the
+ # legacy `#login` structure AA 3.x expects. Mirrors the version probe
+ # ActiveAdmin plugins use (e.g. activeadmin_table_footer's styles.rb).
+ def aa_v4?
+ ::Gem::Version.new(::ActiveAdmin::VERSION) >= ::Gem::Version.new("4.0.0.beta1")
+ end
+
private
def default_logger
diff --git a/lib/generators/active_admin/oidc/install/install_generator.rb b/lib/generators/active_admin/oidc/install/install_generator.rb
index 3fe5b04..e46cbb5 100644
--- a/lib/generators/active_admin/oidc/install/install_generator.rb
+++ b/lib/generators/active_admin/oidc/install/install_generator.rb
@@ -2,6 +2,7 @@
require "rails/generators/base"
require "rails/generators/active_record"
+require "active_admin/version"
module ActiveAdmin
module Oidc
@@ -74,8 +75,13 @@ def create_migration_file
end
def create_view_override
- copy_file "sessions_new.html.erb",
- "app/views/active_admin/devise/sessions/new.html.erb"
+ if aa_v4?
+ copy_file "sessions_new_v4.html.erb",
+ "app/views/active_admin/devise/sessions/new.html.erb"
+ else
+ copy_file "sessions_new.html.erb",
+ "app/views/active_admin/devise/sessions/new.html.erb"
+ end
end
# Non-blocking: the generator completed successfully, but the
@@ -142,6 +148,15 @@ def raw_info_column_type
adapter = (ActiveRecord::Base.connection_db_config.adapter rescue "sqlite3").to_s
adapter.start_with?("postgres") ? ":jsonb" : ":text"
end
+
+ # True when the installed ActiveAdmin is the 4.x line (including the
+ # 4.0.0 prereleases). AA 4 ships a Tailwind-based admin layout, so
+ # the login view override must emit Tailwind markup instead of the
+ # legacy `#login` structure AA 3.x expects. Mirrors the version probe
+ # ActiveAdmin plugins use (e.g. activeadmin_table_footer's styles.rb).
+ def aa_v4?
+ ::Gem::Version.new(::ActiveAdmin::VERSION) >= ::Gem::Version.new("4.0.0.beta1")
+ end
end
end
end
diff --git a/lib/generators/active_admin/oidc/install/templates/sessions_new_v4.html.erb b/lib/generators/active_admin/oidc/install/templates/sessions_new_v4.html.erb
new file mode 100644
index 0000000..3140e29
--- /dev/null
+++ b/lib/generators/active_admin/oidc/install/templates/sessions_new_v4.html.erb
@@ -0,0 +1,12 @@
+
+
+ <%%= site_title %> <%%= set_page_title t('active_admin.devise.login.title') %>
+
+
+ <%%= button_to ActiveAdmin::Oidc.config.login_button_label,
+ "/admin/auth/oidc",
+ method: :post,
+ class: "activeadmin-oidc-login-button w-full",
+ form_class: 'formtastic',
+ data: { turbo: false } %>
+