Derive every mounted path from ActiveAdmin's namespace - #17
Conversation
44defde to
f95a7e2
Compare
There was a problem hiding this comment.
Pull request overview
This PR removes hardcoded /admin assumptions by deriving login/logout/OmniAuth paths (and the post-sign-in landing path) from ActiveAdmin’s configured namespace, with special handling for engine-mounted hosts where Devise’s OmniAuth route prefix and the middleware listening prefix must differ.
Changes:
- Derive
login_path,logout_path, and OmniAuth prefixes fromActiveAdmin.application.default_namespace, while preserving explicit overrides. - Split OmniAuth configuration into a per-strategy middleware
path_prefix:and a Devise route declaration prefix (omniauth_route_prefix) to support mounted engines correctly. - Add/adjust request + isolated-engine specs and update docs/templates to use
ActiveAdmin::Oidc.config.omniauth_path_prefixas the source of truth for browser-visible OmniAuth request paths.
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| spec/unit/configuration_spec.rb | Adds unit coverage for namespace-derived paths and fallback behavior. |
| spec/requests/login_path_helper_spec.rb | Updates regression spec to assert login view uses configured OmniAuth prefix (not hardcoded). |
| spec/requests/disabled_user_persistence_spec.rb | Switches callback posting to configured OmniAuth prefix. |
| spec/requests/after_sign_in_path_spec.rb | Adds specs for post-sign-in landing path resolution via ActiveAdmin root helper. |
| spec/isolated/requests/isolated_engine_callback_spec.rb | Adds full round-trip coverage for isolated engine mounts with split prefixes. |
| spec/dummy_isolated/config/initializers/activeadmin_oidc.rb | Configures isolated dummy to override omniauth_route_prefix engine-relatively. |
| README.md | Documents namespace derivation and the new omniauth_route_prefix behavior for engines. |
| Rakefile | Minor task definition syntax update for spec:all. |
| lib/generators/active_admin/oidc/install/templates/sessions_new.html.erb | Uses gem config for OmniAuth request path in generated view. |
| lib/generators/active_admin/oidc/install/templates/sessions_new_v4.html.erb | Uses gem config for OmniAuth request path in generated v4 view. |
| lib/activeadmin/oidc/engine.rb | Registers strategy using per-strategy path_prefix: and sets Devise route prefix from config. |
| lib/activeadmin/oidc/configuration.rb | Introduces derived path helpers + omniauth_route_prefix with fallback namespace behavior. |
| app/views/active_admin/devise/sessions/new.html.erb | Uses gem config for OmniAuth request path instead of OmniAuth global. |
| app/controllers/active_admin/oidc/devise/omniauth_callbacks_controller.rb | Redirects post-sign-in via ActiveAdmin’s root helper; adds route-set dispatch helper. |
| .rspec | Updates guidance comment about running spec suites. |
| .gitignore | Adds ignore entries and db.yml exception for new dummy app paths. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
f95a7e2 to
08c1c26
Compare
The gem hardcoded `/admin` for the post-sign-in landing page, the SSO login/logout routes and the OmniAuth prefix. A host that renames the namespace (`config.default_namespace = :backoffice`) has no /admin anywhere, so each of those either 404'd or raised. Derive them from `ActiveAdmin.application.default_namespace` instead, and resolve the post-sign-in path through ActiveAdmin's own root helper on whichever route set holds the host's Devise mapping. Engine-mounted hosts need one more distinction. Devise reuses a single setting, `Devise.omniauth_path_prefix`, both to declare its OmniAuth routes and to tell the middleware where to listen; for an engine mounted at a prefix those are different strings, so one value put the callback route at `/admin/admin/auth/oidc/callback` while the middleware redirected to `/admin/auth/oidc/callback`. Drive them separately: `path_prefix:` goes to the strategy directly (honoured over `OmniAuth.config.path_prefix`, which Devise owns), and `omniauth_route_prefix` -- defaulting to `omniauth_path_prefix`, so main-app hosts see no change -- feeds Devise's global. Registering the strategy after the host's config/initializers makes the namespace readable there, so no `after_initialize` hook or Rails 8 lazy-route workaround is needed. Covered by unit specs for the namespace derivation and a full OmniAuth round trip against spec/dummy_isolated. Co-Authored-By: Clanker
The namespace derivation above is exercised by unit specs that stub `ActiveAdmin.application.default_namespace`. This adds the other half: a host that really boots with `config.default_namespace = false`, so the derived login path, OmniAuth prefix and post-sign-in redirect are asserted against a live route table rather than a double. spec/dummy_root/ is spec/dummy/ with that one config line flipped, and no host `root` route — anything the gem redirects to outside the ActiveAdmin route table 404s instead of quietly resolving. The suite pins down exactly what broke in production on such a host: /login (not /admin/login) serves the SSO landing page, /auth is where the middleware listens, and a callback with no stored location lands on / instead of a 404 at /admin. CI now runs one step per dummy app rather than a single combined `spec:all`, so a failure names the host shape that broke.
json 3.0.2 removed the `quirks_mode` keyword that ActiveSupport::JSON.decode/encode still passes to JSON.parse and JSON.generate (activesupport 7.2 and 8.0). CI resolves without a lockfile, so it picked json 3.x up as soon as it was released and every request spec fails with `ArgumentError: unknown keyword: quirks_mode`, regardless of what a branch changes.
08c1c26 to
734488f
Compare
|
Rebased onto Conflict resolutions (against
Added from #19:
Suites, all green on 6/6 matrix legs: |
| # must run in separate processes — invoke them via `rake spec:engine` | ||
| # and `rake spec:isolated`, or all three with `rake spec:all`. | ||
| --exclude-pattern "spec/{engine,isolated,dummy_engine,dummy_isolated}/**/*" |
| # `omniauth_path_prefix`, not `OmniAuth.config.path_prefix`: | ||
| # under an engine mount those two differ by the mount prefix, | ||
| # and this one is the browser-visible path the form posts to. | ||
| "#{omniauth_path_prefix}/#{Engine::PROVIDER_NAME}" |
| ::Devise.omniauth_path_prefix ||= cfg.omniauth_route_prefix | ||
|
|
||
| ::Devise.setup do |devise| | ||
| devise.omniauth :openid_connect, | ||
| name: PROVIDER_NAME, | ||
| path_prefix: cfg.omniauth_path_prefix, |


The gem hardcoded
/adminfor the post-sign-in landing page, the SSO login/logout routes and the OmniAuth prefix. A host that renames the namespace (config.default_namespace = :backoffice) has no /admin anywhere, so each of those either 404'd or raised. Derive them fromActiveAdmin.application.default_namespaceinstead, and resolve the post-sign-in path through ActiveAdmin's own root helper on whichever route set holds the host's Devise mapping.Engine-mounted hosts need one more distinction. Devise reuses a single setting,
Devise.omniauth_path_prefix, both to declare its OmniAuth routes and to tell the middleware where to listen; for an engine mounted at a prefix those are different strings, so one value put the callback route at/admin/admin/auth/oidc/callbackwhile the middleware redirected to/admin/auth/oidc/callback. Drive them separately:path_prefix:goes to the strategy directly (honoured overOmniAuth.config.path_prefix, which Devise owns), andomniauth_route_prefix-- defaulting toomniauth_path_prefix, so main-app hosts see no change -- feeds Devise's global. Registering the strategy after the host's config/initializers makes the namespace readable there, so noafter_initializehook or Rails 8 lazy-route workaround is needed.Covered by unit specs for the namespace derivation and a full OmniAuth round trip against spec/dummy_isolated.