Skip to content

Commit 32443fb

Browse files
committed
Install generator: warn on missing AdminUser wiring, print next steps
Two generator improvements driven by the demo-app testing session: 1. Soft-warn (`say_status :warning`) if app/models/admin_user.rb does not include `:omniauthable` or does not declare `omniauth_providers: [:oidc]`. Non-blocking because the user may be mid-refactor and know what they're doing. 2. Print a "next steps" checklist after a successful run covering the host-app wiring the generator cannot touch: uncommenting `config.authentication_method` / `config.current_user_method` in active_admin.rb, adding `:omniauthable, omniauth_providers: [:oidc]` to AdminUser, filling in issuer/client_id, and running db:migrate. Both were footguns during end-to-end testing with a fresh ActiveAdmin host — commented-out `authentication_method` left /admin publicly accessible and rendered the utility nav without a logout button, which is exactly the state this checklist now warns about.
1 parent 2b72e84 commit 32443fb

2 files changed

Lines changed: 142 additions & 2 deletions

File tree

lib/generators/active_admin/oidc/install/install_generator.rb

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,62 @@ def create_view_override
7878
"app/views/active_admin/devise/sessions/new.html.erb"
7979
end
8080

81+
# Non-blocking: the generator completed successfully, but the
82+
# host AdminUser may be missing the Devise modules the gem needs.
83+
# We warn rather than hard-fail because a mid-refactor user may
84+
# know exactly what they're doing.
85+
def warn_missing_admin_user_wiring
86+
admin_user_path = File.join(destination_root, "app/models/admin_user.rb")
87+
return unless File.exist?(admin_user_path)
88+
89+
contents = File.read(admin_user_path)
90+
91+
unless contents.match?(/:omniauthable/)
92+
say_status :warning,
93+
"app/models/admin_user.rb does not include :omniauthable — " \
94+
"add `:omniauthable, omniauth_providers: [:oidc]` to your `devise` call.",
95+
:yellow
96+
end
97+
98+
unless contents.match?(/omniauth_providers\s*:\s*\[\s*:oidc/)
99+
say_status :warning,
100+
"app/models/admin_user.rb does not declare `omniauth_providers: [:oidc]` — " \
101+
"the gem's callback controller will not be reachable without it.",
102+
:yellow
103+
end
104+
end
105+
106+
# Print a short checklist of the host-app wiring the generator
107+
# can't do itself. These are the footguns that cost us an hour
108+
# the first time we wired a fresh demo app: commented-out
109+
# `authentication_method` / `current_user_method` in the
110+
# ActiveAdmin initializer, and forgetting to migrate.
111+
def print_next_steps
112+
say ""
113+
say "=" * 60, :green
114+
say "activeadmin-oidc: next steps", :green
115+
say "=" * 60, :green
116+
say <<~STEPS
117+
1. In config/initializers/active_admin.rb, uncomment:
118+
config.authentication_method = :authenticate_admin_user!
119+
config.current_user_method = :current_admin_user
120+
Without these, /admin is public and the utility nav
121+
(including the logout button) renders empty.
122+
123+
2. In app/models/admin_user.rb, make sure the devise call
124+
includes:
125+
:omniauthable, omniauth_providers: [:oidc]
126+
127+
3. Fill in the generated config/initializers/activeadmin_oidc.rb
128+
with your issuer and client_id (plus client_secret if you
129+
are NOT using PKCE public-client mode).
130+
131+
4. Apply the generated migration:
132+
bin/rails db:migrate
133+
STEPS
134+
say "=" * 60, :green
135+
end
136+
81137
private
82138

83139
# Postgres gets `jsonb` (fast, indexable), everything else

spec/generators/install_generator_spec.rb

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,18 @@ def run_generator(args = [])
5454
# Instantiate directly rather than going through `start` so that
5555
# `Thor::Error` raised in preflight propagates to the spec instead
5656
# of being caught by Thor's CLI wrapper. Redirect $stdout so the
57-
# "create file" log lines don't pollute rspec output.
57+
# "create file" log lines don't pollute rspec output, but capture
58+
# it so tests can assert on warnings and next-steps output.
5859
generator = described_class.new(args, [], destination_root: destination_root)
5960
orig_stdout = $stdout
60-
$stdout = StringIO.new
61+
captured = StringIO.new
62+
$stdout = captured
6163
begin
6264
generator.invoke_all
6365
ensure
6466
$stdout = orig_stdout
6567
end
68+
captured.string
6669
end
6770

6871
describe "initializer" do
@@ -190,4 +193,85 @@ def run_generator(args = [])
190193
expect { run_generator }.to raise_error(Thor::Error, /activeadmin/)
191194
end
192195
end
196+
197+
describe "warnings for AdminUser devise setup" do
198+
# These are soft checks: the generator still runs to completion,
199+
# but prints a warning pointing the user at the missing wiring.
200+
# Hard-failing would be too aggressive — the user may be mid-refactor
201+
# and know what they're doing.
202+
203+
it "warns when AdminUser does not include :omniauthable" do
204+
File.write(
205+
File.join(destination_root, "app/models/admin_user.rb"),
206+
<<~RUBY
207+
class AdminUser < ApplicationRecord
208+
devise :database_authenticatable, :rememberable
209+
end
210+
RUBY
211+
)
212+
213+
output = run_generator
214+
expect(output).to match(/:omniauthable/)
215+
expect(output).to match(/admin_user\.rb/i)
216+
end
217+
218+
it "warns when AdminUser does not declare omniauth_providers: [:oidc]" do
219+
File.write(
220+
File.join(destination_root, "app/models/admin_user.rb"),
221+
<<~RUBY
222+
class AdminUser < ApplicationRecord
223+
devise :database_authenticatable, :omniauthable
224+
end
225+
RUBY
226+
)
227+
228+
output = run_generator
229+
expect(output).to match(/omniauth_providers.*:oidc/)
230+
end
231+
232+
it "does NOT warn when AdminUser is already wired for oidc omniauth" do
233+
File.write(
234+
File.join(destination_root, "app/models/admin_user.rb"),
235+
<<~RUBY
236+
class AdminUser < ApplicationRecord
237+
devise :database_authenticatable,
238+
:omniauthable, omniauth_providers: [:oidc]
239+
end
240+
RUBY
241+
)
242+
243+
output = run_generator
244+
expect(output).not_to match(/warning.*omniauthable/i)
245+
expect(output).not_to match(/warning.*omniauth_providers/i)
246+
end
247+
end
248+
249+
describe "post-install next-steps message" do
250+
it "prints a next-steps section after a successful run" do
251+
output = run_generator
252+
expect(output).to match(/next steps/i)
253+
end
254+
255+
it "reminds the host to uncomment authentication_method in active_admin.rb" do
256+
output = run_generator
257+
expect(output).to include("authentication_method")
258+
expect(output).to include(":authenticate_admin_user!")
259+
end
260+
261+
it "reminds the host to uncomment current_user_method in active_admin.rb" do
262+
output = run_generator
263+
expect(output).to include("current_user_method")
264+
expect(output).to include(":current_admin_user")
265+
end
266+
267+
it "reminds the host to run the generated migration" do
268+
output = run_generator
269+
expect(output).to match(/db:migrate|rails\s+db:migrate/)
270+
end
271+
272+
it "reminds the host to set AdminUser :omniauthable with omniauth_providers: [:oidc]" do
273+
output = run_generator
274+
expect(output).to include("omniauth_providers: [:oidc]")
275+
end
276+
end
193277
end

0 commit comments

Comments
 (0)