verikloak-audience 0.2.9 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 53894e2af5f290a98ec6f438b9d0271e1f8e86d18c6404c9b0394c5cd5741312
4
- data.tar.gz: 0cc799a43b2559f34113e6d738d1e2ee004c1292c86115dc83918ca32aeef04f
3
+ metadata.gz: d97d79e3f6ccd8f2c920cc7dcb66612e9edbd577ba4be2f5948eddd16145dd9b
4
+ data.tar.gz: 4517ee945923ec595fa7447f33dd0e9370cc72a2a561bc04d4f910efed018595
5
5
  SHA512:
6
- metadata.gz: 9536f08a7ce2f5de4113483215386221dec1867c6affbea7a0e3074239017c1d7e0d4135476f72cf45cbda1de2fc17781fdf9662d038eb110afdb336a5ee6bb3
7
- data.tar.gz: 5730013314cd5dd393c9936256a5fe31cb3aa13fac4c3dda6dabb7ca308424167235d0482167f2cc92c13e26ee5bdef23eaeddab5f01b7898ea31474aeb3211d
6
+ metadata.gz: 83c14846297272179ccf6f4480dab677c82be3d21b32a6c374c3b40fc5be04dd0cf9c9c439457e9dd33d4b4a9fca393aca31b7104b4282479b872ad8987c8632
7
+ data.tar.gz: e2e125eab982f983e6447166bcd6b9d9413f15573301335f15ef53ba0bafb6d07020848ec942e9b532db69b29ab3fc6280ae9fc6f74d12ff9786a39fc64dccde
data/CHANGELOG.md CHANGED
@@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ---
9
9
 
10
+ ## [0.3.0] - 2026-01-01
11
+
12
+ ### Fixed
13
+ - **Rails 8.x+ middleware insertion**: Fixed automatic middleware insertion not working in Rails 8.x+ due to queued middleware operations not being visible via `include?` checks.
14
+
15
+ ### Changed
16
+ - Railtie initializer now specifies `before: :build_middleware_stack` to ensure middleware insertion is queued before stack construction.
17
+ - Middleware insertion now uses `app.config.middleware` instead of `app.middleware` for more reliable queuing in Rails 8.x+.
18
+ - Extracted `middleware_not_found_error?` method to handle error detection across Rails versions (Rails 7's `MiddlewareNotFound` and Rails 8+'s `RuntimeError`).
19
+
20
+ ### Added
21
+ - `@middleware_insertion_attempted` class variable to prevent duplicate middleware insertion when both railtie and generator initializer run.
22
+ - `reset_middleware_insertion_flag!` method for testing purposes.
23
+ - Support for alternative error message patterns (`"does not exist"`, `/middleware.*not found/i`) for future Rails version compatibility.
24
+ - Comprehensive test coverage for:
25
+ - `include?` early return when middleware is already present
26
+ - Duplicate insertion prevention via flag
27
+ - Rails 7 `MiddlewareNotFound` exception handling
28
+ - Alternative error message patterns
29
+ - Unexpected exception re-raising
30
+
10
31
  ## [0.2.9] - 2025-12-31
11
32
 
12
33
  ### Added
@@ -2,6 +2,10 @@
2
2
 
3
3
  # Insert the audience middleware after the core Verikloak middleware once it
4
4
  # has been loaded into the application.
5
+ #
6
+ # The Railtie's insert_middleware method includes internal guards to prevent
7
+ # duplicate insertion when both the railtie initializer and this generated
8
+ # initializer are loaded. This is safe to call multiple times.
5
9
  if defined?(Rails) && Rails.respond_to?(:application)
6
10
  Verikloak::Audience::Railtie.insert_middleware(Rails.application)
7
11
  end
@@ -28,7 +28,9 @@ module Verikloak
28
28
  # when available.
29
29
  #
30
30
  # @param app [Rails::Application] the Rails application instance
31
- initializer 'verikloak_audience.middleware' do |app|
31
+ initializer 'verikloak_audience.middleware',
32
+ after: 'verikloak.configure',
33
+ before: :build_middleware_stack do |app|
32
34
  # Insert automatically after core verikloak if present
33
35
  self.class.insert_middleware(app)
34
36
  end
@@ -42,6 +44,17 @@ module Verikloak
42
44
  end
43
45
  end
44
46
 
47
+ # Tracks whether middleware insertion has been attempted to prevent
48
+ # duplicate insertions when both railtie and generator initializer run.
49
+ # In Rails 8.x+, middleware operations may be queued and `include?` may
50
+ # not reflect pending insertions, so we use this flag as an additional
51
+ # safeguard.
52
+ @middleware_insertion_attempted = false
53
+
54
+ class << self
55
+ attr_accessor :middleware_insertion_attempted
56
+ end
57
+
45
58
  # Performs the insertion into the middleware stack when the core
46
59
  # Verikloak middleware is available and already present. Extracted for
47
60
  # testability without requiring a full Rails boot process.
@@ -49,22 +62,72 @@ module Verikloak
49
62
  # Insert the audience middleware after the base Verikloak middleware when
50
63
  # both are available on the stack.
51
64
  #
65
+ # In Rails 8.x+, middleware stack operations may be queued rather than
66
+ # immediately applied, so `include?` checks may return false even when
67
+ # the middleware will be inserted. We use `insert_after` with exception
68
+ # handling to gracefully handle this case.
69
+ #
52
70
  # @param app [#middleware] An object exposing a Rack middleware stack via `#middleware`.
53
71
  # @return [void]
54
72
  def self.insert_middleware(app)
55
73
  return unless defined?(::Verikloak::Middleware)
56
74
 
57
- middleware_stack = app.middleware
58
- return unless middleware_stack.respond_to?(:include?)
75
+ # Skip if we have already attempted insertion (handles Rails 8+ queued operations)
76
+ return if middleware_insertion_attempted
59
77
 
60
- return if middleware_stack.include?(::Verikloak::Audience::Middleware)
78
+ # Use app.config.middleware for queued operations in Rails 8.x+
79
+ # This ensures the insert_after operation is queued and applied during
80
+ # build_middleware_stack, maintaining proper ordering with verikloak-rails
81
+ middleware_stack = app.respond_to?(:config) ? app.config.middleware : app.middleware
61
82
 
62
- unless middleware_stack.include?(::Verikloak::Middleware)
63
- warn_missing_core_middleware
83
+ # Skip if already present (avoid duplicate insertion)
84
+ if middleware_stack.respond_to?(:include?) &&
85
+ middleware_stack.include?(::Verikloak::Audience::Middleware)
64
86
  return
65
87
  end
66
88
 
67
- middleware_stack.insert_after ::Verikloak::Middleware, ::Verikloak::Audience::Middleware
89
+ # Mark as attempted before insertion to prevent concurrent/subsequent calls
90
+ self.middleware_insertion_attempted = true
91
+
92
+ # Attempt to insert after the core Verikloak middleware.
93
+ # In Rails 8.x+, the middleware may be queued but not yet visible via include?,
94
+ # so we try the insertion and handle any exceptions gracefully.
95
+ begin
96
+ middleware_stack.insert_after ::Verikloak::Middleware, ::Verikloak::Audience::Middleware
97
+ rescue StandardError => e
98
+ # Handle middleware not found errors (varies by Rails version):
99
+ # - Rails 8+: RuntimeError with "No such middleware" message
100
+ # - Earlier: ActionDispatch::MiddlewareStack::MiddlewareNotFound
101
+ raise unless middleware_not_found_error?(e)
102
+
103
+ warn_missing_core_middleware
104
+ end
105
+ end
106
+
107
+ # Determines if the given exception indicates a middleware not found error.
108
+ # This handles variations across Rails versions:
109
+ # - Rails 8+: RuntimeError with "No such middleware" message
110
+ # - Rails 7 and earlier: ActionDispatch::MiddlewareStack::MiddlewareNotFound
111
+ #
112
+ # @param error [StandardError] the exception to check
113
+ # @return [Boolean] true if the error indicates missing middleware
114
+ def self.middleware_not_found_error?(error)
115
+ # Check exception class name (works for Rails 7's MiddlewareNotFound)
116
+ return true if error.class.name.to_s.include?('MiddlewareNotFound')
117
+
118
+ # Check message patterns for Rails 8+ RuntimeError
119
+ message = error.message.to_s
120
+ message.include?('No such middleware') ||
121
+ message.include?('does not exist') ||
122
+ message.match?(/middleware.*not found/i)
123
+ end
124
+
125
+ # Resets the insertion flag. Primarily used for testing to allow
126
+ # multiple insertion attempts within the same process.
127
+ #
128
+ # @return [void]
129
+ def self.reset_middleware_insertion_flag!
130
+ self.middleware_insertion_attempted = false
68
131
  end
69
132
 
70
133
  WARNING_MESSAGE = <<~MSG
@@ -4,6 +4,6 @@ module Verikloak
4
4
  module Audience
5
5
  # Current gem version.
6
6
  # @return [String]
7
- VERSION = '0.2.9'
7
+ VERSION = '0.3.0'
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: verikloak-audience
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.9
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - taiyaky
@@ -76,7 +76,7 @@ metadata:
76
76
  source_code_uri: https://github.com/taiyaky/verikloak-audience
77
77
  changelog_uri: https://github.com/taiyaky/verikloak-audience/blob/main/CHANGELOG.md
78
78
  bug_tracker_uri: https://github.com/taiyaky/verikloak-audience/issues
79
- documentation_uri: https://rubydoc.info/gems/verikloak-audience/0.2.9
79
+ documentation_uri: https://rubydoc.info/gems/verikloak-audience/0.3.0
80
80
  rubygems_mfa_required: 'true'
81
81
  rdoc_options: []
82
82
  require_paths: