a2a-ruby 1.0.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.
Files changed (128) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +137 -0
  4. data/.simplecov +46 -0
  5. data/.yardopts +10 -0
  6. data/CHANGELOG.md +33 -0
  7. data/CODE_OF_CONDUCT.md +128 -0
  8. data/CONTRIBUTING.md +165 -0
  9. data/Gemfile +43 -0
  10. data/Guardfile +34 -0
  11. data/LICENSE.txt +21 -0
  12. data/PUBLISHING_CHECKLIST.md +214 -0
  13. data/README.md +171 -0
  14. data/Rakefile +165 -0
  15. data/docs/agent_execution.md +309 -0
  16. data/docs/api_reference.md +792 -0
  17. data/docs/configuration.md +780 -0
  18. data/docs/events.md +475 -0
  19. data/docs/getting_started.md +668 -0
  20. data/docs/integration.md +262 -0
  21. data/docs/server_apps.md +621 -0
  22. data/docs/troubleshooting.md +765 -0
  23. data/lib/a2a/client/api_methods.rb +263 -0
  24. data/lib/a2a/client/auth/api_key.rb +161 -0
  25. data/lib/a2a/client/auth/interceptor.rb +288 -0
  26. data/lib/a2a/client/auth/jwt.rb +189 -0
  27. data/lib/a2a/client/auth/oauth2.rb +146 -0
  28. data/lib/a2a/client/auth.rb +137 -0
  29. data/lib/a2a/client/base.rb +316 -0
  30. data/lib/a2a/client/config.rb +210 -0
  31. data/lib/a2a/client/connection_pool.rb +233 -0
  32. data/lib/a2a/client/http_client.rb +524 -0
  33. data/lib/a2a/client/json_rpc_handler.rb +136 -0
  34. data/lib/a2a/client/middleware/circuit_breaker_interceptor.rb +245 -0
  35. data/lib/a2a/client/middleware/logging_interceptor.rb +371 -0
  36. data/lib/a2a/client/middleware/rate_limit_interceptor.rb +142 -0
  37. data/lib/a2a/client/middleware/retry_interceptor.rb +161 -0
  38. data/lib/a2a/client/middleware.rb +116 -0
  39. data/lib/a2a/client/performance_tracker.rb +60 -0
  40. data/lib/a2a/configuration/defaults.rb +34 -0
  41. data/lib/a2a/configuration/environment_loader.rb +76 -0
  42. data/lib/a2a/configuration/file_loader.rb +115 -0
  43. data/lib/a2a/configuration/inheritance.rb +101 -0
  44. data/lib/a2a/configuration/validator.rb +180 -0
  45. data/lib/a2a/configuration.rb +201 -0
  46. data/lib/a2a/errors.rb +291 -0
  47. data/lib/a2a/modules.rb +50 -0
  48. data/lib/a2a/monitoring/alerting.rb +490 -0
  49. data/lib/a2a/monitoring/distributed_tracing.rb +398 -0
  50. data/lib/a2a/monitoring/health_endpoints.rb +204 -0
  51. data/lib/a2a/monitoring/metrics_collector.rb +438 -0
  52. data/lib/a2a/monitoring.rb +463 -0
  53. data/lib/a2a/plugin.rb +358 -0
  54. data/lib/a2a/plugin_manager.rb +159 -0
  55. data/lib/a2a/plugins/example_auth.rb +81 -0
  56. data/lib/a2a/plugins/example_middleware.rb +118 -0
  57. data/lib/a2a/plugins/example_transport.rb +76 -0
  58. data/lib/a2a/protocol/agent_card.rb +8 -0
  59. data/lib/a2a/protocol/agent_card_server.rb +584 -0
  60. data/lib/a2a/protocol/capability.rb +496 -0
  61. data/lib/a2a/protocol/json_rpc.rb +254 -0
  62. data/lib/a2a/protocol/message.rb +8 -0
  63. data/lib/a2a/protocol/task.rb +8 -0
  64. data/lib/a2a/rails/a2a_controller.rb +258 -0
  65. data/lib/a2a/rails/controller_helpers.rb +499 -0
  66. data/lib/a2a/rails/engine.rb +167 -0
  67. data/lib/a2a/rails/generators/agent_generator.rb +311 -0
  68. data/lib/a2a/rails/generators/install_generator.rb +209 -0
  69. data/lib/a2a/rails/generators/migration_generator.rb +232 -0
  70. data/lib/a2a/rails/generators/templates/add_a2a_indexes.rb +57 -0
  71. data/lib/a2a/rails/generators/templates/agent_controller.rb +122 -0
  72. data/lib/a2a/rails/generators/templates/agent_controller_spec.rb +160 -0
  73. data/lib/a2a/rails/generators/templates/agent_readme.md +200 -0
  74. data/lib/a2a/rails/generators/templates/create_a2a_push_notification_configs.rb +68 -0
  75. data/lib/a2a/rails/generators/templates/create_a2a_tasks.rb +83 -0
  76. data/lib/a2a/rails/generators/templates/example_agent_controller.rb +228 -0
  77. data/lib/a2a/rails/generators/templates/initializer.rb +108 -0
  78. data/lib/a2a/rails/generators/templates/push_notification_config_model.rb +228 -0
  79. data/lib/a2a/rails/generators/templates/task_model.rb +200 -0
  80. data/lib/a2a/rails/tasks/a2a.rake +228 -0
  81. data/lib/a2a/server/a2a_methods.rb +520 -0
  82. data/lib/a2a/server/agent.rb +537 -0
  83. data/lib/a2a/server/agent_execution/agent_executor.rb +279 -0
  84. data/lib/a2a/server/agent_execution/request_context.rb +219 -0
  85. data/lib/a2a/server/apps/rack_app.rb +311 -0
  86. data/lib/a2a/server/apps/sinatra_app.rb +261 -0
  87. data/lib/a2a/server/default_request_handler.rb +350 -0
  88. data/lib/a2a/server/events/event_consumer.rb +116 -0
  89. data/lib/a2a/server/events/event_queue.rb +226 -0
  90. data/lib/a2a/server/example_agent.rb +248 -0
  91. data/lib/a2a/server/handler.rb +281 -0
  92. data/lib/a2a/server/middleware/authentication_middleware.rb +212 -0
  93. data/lib/a2a/server/middleware/cors_middleware.rb +171 -0
  94. data/lib/a2a/server/middleware/logging_middleware.rb +362 -0
  95. data/lib/a2a/server/middleware/rate_limit_middleware.rb +382 -0
  96. data/lib/a2a/server/middleware.rb +213 -0
  97. data/lib/a2a/server/push_notification_manager.rb +327 -0
  98. data/lib/a2a/server/request_handler.rb +136 -0
  99. data/lib/a2a/server/storage/base.rb +141 -0
  100. data/lib/a2a/server/storage/database.rb +266 -0
  101. data/lib/a2a/server/storage/memory.rb +274 -0
  102. data/lib/a2a/server/storage/redis.rb +320 -0
  103. data/lib/a2a/server/storage.rb +38 -0
  104. data/lib/a2a/server/task_manager.rb +534 -0
  105. data/lib/a2a/transport/grpc.rb +481 -0
  106. data/lib/a2a/transport/http.rb +415 -0
  107. data/lib/a2a/transport/sse.rb +499 -0
  108. data/lib/a2a/types/agent_card.rb +540 -0
  109. data/lib/a2a/types/artifact.rb +99 -0
  110. data/lib/a2a/types/base_model.rb +223 -0
  111. data/lib/a2a/types/events.rb +117 -0
  112. data/lib/a2a/types/message.rb +106 -0
  113. data/lib/a2a/types/part.rb +288 -0
  114. data/lib/a2a/types/push_notification.rb +139 -0
  115. data/lib/a2a/types/security.rb +167 -0
  116. data/lib/a2a/types/task.rb +154 -0
  117. data/lib/a2a/types.rb +88 -0
  118. data/lib/a2a/utils/helpers.rb +245 -0
  119. data/lib/a2a/utils/message_buffer.rb +278 -0
  120. data/lib/a2a/utils/performance.rb +247 -0
  121. data/lib/a2a/utils/rails_detection.rb +97 -0
  122. data/lib/a2a/utils/structured_logger.rb +306 -0
  123. data/lib/a2a/utils/time_helpers.rb +167 -0
  124. data/lib/a2a/utils/validation.rb +8 -0
  125. data/lib/a2a/version.rb +6 -0
  126. data/lib/a2a-rails.rb +58 -0
  127. data/lib/a2a.rb +198 -0
  128. metadata +437 -0
@@ -0,0 +1,288 @@
1
+ # frozen_string_literal: true
2
+
3
+ module A2A
4
+ module Types
5
+ ##
6
+ # Base class for message parts (discriminated union)
7
+ #
8
+ # Parts represent different types of content within a message.
9
+ # This is an abstract base class - use TextPart, FilePart, or DataPart.
10
+ #
11
+ class Part < A2A::Types::BaseModel
12
+ attr_reader :kind, :metadata
13
+
14
+ ##
15
+ # Create a part from a hash (factory method)
16
+ #
17
+ # @param hash [Hash] The hash representation
18
+ # @return [Part] The appropriate part subclass instance
19
+ def self.from_h(hash)
20
+ return hash if hash.is_a?(Part) # Already a Part instance
21
+ return nil if hash.nil?
22
+
23
+ kind = hash[:kind] || hash["kind"]
24
+ case kind
25
+ when PART_KIND_TEXT
26
+ TextPart.from_h(hash)
27
+ when PART_KIND_FILE
28
+ FilePart.from_h(hash)
29
+ when PART_KIND_DATA
30
+ DataPart.from_h(hash)
31
+ else
32
+ raise ArgumentError, "Unknown part kind: #{kind}"
33
+ end
34
+ end
35
+
36
+ protected
37
+
38
+ def initialize(kind:, metadata: nil)
39
+ @kind = kind
40
+ @metadata = metadata
41
+ validate!
42
+ end
43
+
44
+ private
45
+
46
+ def validate!
47
+ validate_required(:kind)
48
+ validate_inclusion(:kind, VALID_PART_KINDS)
49
+ end
50
+ end
51
+
52
+ ##
53
+ # Represents a text part in a message
54
+ #
55
+ class TextPart < Part
56
+ attr_reader :text
57
+
58
+ ##
59
+ # Initialize a new text part
60
+ #
61
+ # @param text [String] The text content
62
+ # @param metadata [Hash, nil] Additional metadata
63
+ def initialize(text:, metadata: nil)
64
+ @text = text
65
+ super(kind: PART_KIND_TEXT, metadata: metadata)
66
+ end
67
+
68
+ ##
69
+ # Create a TextPart from a hash
70
+ #
71
+ # @param hash [Hash] The hash representation
72
+ # @return [TextPart] The new instance
73
+ def self.from_h(hash)
74
+ return hash if hash.is_a?(TextPart)
75
+ return nil if hash.nil?
76
+
77
+ # Convert string keys to symbols and snake_case camelCase keys
78
+ normalized_hash = {}
79
+ hash.each do |key, value|
80
+ snake_key = BaseModel.underscore(key.to_s).to_sym
81
+ normalized_hash[snake_key] = value unless snake_key == :kind
82
+ end
83
+
84
+ new(**normalized_hash)
85
+ end
86
+
87
+ private
88
+
89
+ def validate!
90
+ super
91
+ validate_required(:text)
92
+ validate_type(:text, String)
93
+ end
94
+ end
95
+
96
+ ##
97
+ # Represents a file part in a message
98
+ #
99
+ class FilePart < Part
100
+ attr_reader :file
101
+
102
+ ##
103
+ # Initialize a new file part
104
+ #
105
+ # @param file [FileBase] The file object
106
+ # @param metadata [Hash, nil] Additional metadata
107
+ def initialize(file:, metadata: nil)
108
+ @file = file.is_a?(Hash) ? FileBase.from_h(file) : file
109
+ super(kind: PART_KIND_FILE, metadata: metadata)
110
+ end
111
+
112
+ ##
113
+ # Create a FilePart from a hash
114
+ #
115
+ # @param hash [Hash] The hash representation
116
+ # @return [FilePart] The new instance
117
+ def self.from_h(hash)
118
+ return hash if hash.is_a?(FilePart)
119
+ return nil if hash.nil?
120
+
121
+ # Convert string keys to symbols and snake_case camelCase keys
122
+ normalized_hash = {}
123
+ hash.each do |key, value|
124
+ snake_key = BaseModel.underscore(key.to_s).to_sym
125
+ normalized_hash[snake_key] = value unless snake_key == :kind
126
+ end
127
+
128
+ new(**normalized_hash)
129
+ end
130
+
131
+ private
132
+
133
+ def validate!
134
+ super
135
+ validate_required(:file)
136
+ validate_type(:file, FileBase)
137
+ end
138
+ end
139
+
140
+ ##
141
+ # Represents a data part in a message
142
+ #
143
+ class DataPart < Part
144
+ attr_reader :data
145
+
146
+ ##
147
+ # Initialize a new data part
148
+ #
149
+ # @param data [Object] The data content (any JSON-serializable object)
150
+ # @param metadata [Hash, nil] Additional metadata
151
+ def initialize(data:, metadata: nil)
152
+ @data = data
153
+ super(kind: PART_KIND_DATA, metadata: metadata)
154
+ end
155
+
156
+ ##
157
+ # Create a DataPart from a hash
158
+ #
159
+ # @param hash [Hash] The hash representation
160
+ # @return [DataPart] The new instance
161
+ def self.from_h(hash)
162
+ return hash if hash.is_a?(DataPart)
163
+ return nil if hash.nil?
164
+
165
+ # Convert string keys to symbols and snake_case camelCase keys
166
+ normalized_hash = {}
167
+ hash.each do |key, value|
168
+ snake_key = BaseModel.underscore(key.to_s).to_sym
169
+ normalized_hash[snake_key] = value unless snake_key == :kind
170
+ end
171
+
172
+ new(**normalized_hash)
173
+ end
174
+
175
+ private
176
+
177
+ def validate!
178
+ super
179
+ validate_required(:data)
180
+ end
181
+ end
182
+
183
+ ##
184
+ # Base class for file representations
185
+ #
186
+ class FileBase < A2A::Types::BaseModel
187
+ ##
188
+ # Create a file from a hash (factory method)
189
+ #
190
+ # @param hash [Hash] The hash representation
191
+ # @return [FileBase] The appropriate file subclass instance
192
+ def self.from_h(hash)
193
+ return nil if hash.nil?
194
+
195
+ if hash.key?(:bytes) || hash.key?("bytes")
196
+ FileWithBytes.from_h(hash)
197
+ elsif hash.key?(:uri) || hash.key?("uri")
198
+ FileWithUri.from_h(hash)
199
+ else
200
+ raise ArgumentError, "File must have either 'bytes' or 'uri'"
201
+ end
202
+ end
203
+ end
204
+
205
+ ##
206
+ # Represents a file with base64-encoded bytes
207
+ #
208
+ class FileWithBytes < FileBase
209
+ attr_reader :name, :mime_type, :bytes
210
+
211
+ ##
212
+ # Initialize a new file with bytes
213
+ #
214
+ # @param name [String] The file name
215
+ # @param mime_type [String] The MIME type
216
+ # @param bytes [String] Base64-encoded file content
217
+ def initialize(name:, mime_type:, bytes:)
218
+ @name = name
219
+ @mime_type = mime_type
220
+ @bytes = bytes
221
+ validate!
222
+ end
223
+
224
+ ##
225
+ # Get the decoded file content
226
+ #
227
+ # @return [String] The decoded binary content
228
+ def content
229
+ require "base64"
230
+ Base64.decode64(@bytes)
231
+ end
232
+
233
+ ##
234
+ # Get the file size in bytes
235
+ #
236
+ # @return [Integer] The file size
237
+ def size
238
+ content.bytesize
239
+ end
240
+
241
+ private
242
+
243
+ def validate!
244
+ validate_required(:name, :mime_type, :bytes)
245
+ validate_type(:name, String)
246
+ validate_type(:mime_type, String)
247
+ validate_type(:bytes, String)
248
+ end
249
+ end
250
+
251
+ ##
252
+ # Represents a file with a URI reference
253
+ #
254
+ class FileWithUri < FileBase
255
+ attr_reader :name, :mime_type, :uri
256
+
257
+ ##
258
+ # Initialize a new file with URI
259
+ #
260
+ # @param name [String] The file name
261
+ # @param mime_type [String] The MIME type
262
+ # @param uri [String] The file URI
263
+ def initialize(name:, mime_type:, uri:)
264
+ @name = name
265
+ @mime_type = mime_type
266
+ @uri = uri
267
+ validate!
268
+ end
269
+
270
+ private
271
+
272
+ def validate!
273
+ validate_required(:name, :mime_type, :uri)
274
+ validate_type(:name, String)
275
+ validate_type(:mime_type, String)
276
+ validate_type(:uri, String)
277
+
278
+ # Basic URI validation
279
+ begin
280
+ require "uri"
281
+ URI.parse(@uri)
282
+ rescue URI::InvalidURIError
283
+ raise ArgumentError, "Invalid URI: #{@uri}"
284
+ end
285
+ end
286
+ end
287
+ end
288
+ end
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ module A2A
4
+ module Types
5
+ ##
6
+ # Represents a push notification configuration
7
+ #
8
+ # Push notification configs define how and where to send notifications
9
+ # about task updates and other events.
10
+ #
11
+ class PushNotificationConfig < A2A::Types::BaseModel
12
+ attr_reader :id, :url, :token, :authentication
13
+
14
+ ##
15
+ # Initialize a new push notification config
16
+ #
17
+ # @param url [String] The webhook URL
18
+ # @param id [String, nil] Optional config identifier
19
+ # @param token [String, nil] Optional authentication token
20
+ # @param authentication [Hash, nil] Authentication configuration
21
+ def initialize(url:, id: nil, token: nil, authentication: nil)
22
+ @url = url
23
+ @id = id
24
+ @token = token
25
+ @authentication = authentication
26
+
27
+ validate!
28
+ end
29
+
30
+ ##
31
+ # Check if authentication is configured
32
+ #
33
+ # @return [Boolean] True if authentication is present
34
+ def authenticated?
35
+ !@token.nil? || !@authentication.nil?
36
+ end
37
+
38
+ ##
39
+ # Get authentication headers for webhook requests
40
+ #
41
+ # @return [Hash] Headers to include in webhook requests
42
+ def auth_headers
43
+ headers = {}
44
+
45
+ headers["Authorization"] = "Bearer #{@token}" if @token
46
+
47
+ if @authentication.is_a?(Hash)
48
+ case @authentication["type"]
49
+ when "bearer"
50
+ headers["Authorization"] = "Bearer #{@authentication['token']}"
51
+ when "basic"
52
+ require "base64"
53
+ credentials = Base64.strict_encode64("#{@authentication['username']}:#{@authentication['password']}")
54
+ headers["Authorization"] = "Basic #{credentials}"
55
+ when "api_key"
56
+ key_name = @authentication["key_name"] || "X-API-Key"
57
+ headers[key_name] = @authentication["api_key"]
58
+ end
59
+ end
60
+
61
+ headers
62
+ end
63
+
64
+ private
65
+
66
+ def validate!
67
+ validate_required(:url)
68
+ validate_type(:url, String)
69
+
70
+ # Basic URL validation
71
+ begin
72
+ require "uri"
73
+ uri = URI.parse(@url)
74
+ raise ArgumentError, "URL must be HTTP or HTTPS" unless uri.is_a?(URI::HTTP) || uri.is_a?(URI::HTTPS)
75
+ rescue URI::InvalidURIError
76
+ raise ArgumentError, "Invalid URL: #{@url}"
77
+ end
78
+ end
79
+ end
80
+
81
+ ##
82
+ # Represents a task-specific push notification configuration
83
+ #
84
+ # Links a task to a push notification configuration for receiving
85
+ # updates about that specific task.
86
+ #
87
+ class TaskPushNotificationConfig < A2A::Types::BaseModel
88
+ attr_reader :task_id, :push_notification_config
89
+
90
+ ##
91
+ # Initialize a new task push notification config
92
+ #
93
+ # @param task_id [String] The task identifier
94
+ # @param push_notification_config [PushNotificationConfig, Hash] The notification config
95
+ def initialize(task_id:, push_notification_config:)
96
+ @task_id = task_id
97
+ @push_notification_config = if push_notification_config.is_a?(PushNotificationConfig)
98
+ push_notification_config
99
+ else
100
+ PushNotificationConfig.from_h(push_notification_config)
101
+ end
102
+
103
+ validate!
104
+ end
105
+
106
+ ##
107
+ # Get the webhook URL
108
+ #
109
+ # @return [String] The webhook URL
110
+ def webhook_url
111
+ @push_notification_config.url
112
+ end
113
+
114
+ ##
115
+ # Get authentication headers
116
+ #
117
+ # @return [Hash] Authentication headers
118
+ def auth_headers
119
+ @push_notification_config.auth_headers
120
+ end
121
+
122
+ ##
123
+ # Check if authentication is configured
124
+ #
125
+ # @return [Boolean] True if authentication is present
126
+ def authenticated?
127
+ @push_notification_config.authenticated?
128
+ end
129
+
130
+ private
131
+
132
+ def validate!
133
+ validate_required(:task_id, :push_notification_config)
134
+ validate_type(:task_id, String)
135
+ validate_type(:push_notification_config, PushNotificationConfig)
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,167 @@
1
+ # frozen_string_literal: true
2
+
3
+ module A2A
4
+ module Types
5
+ ##
6
+ # Base class for security schemes (discriminated union)
7
+ #
8
+ # Security schemes define how authentication and authorization
9
+ # should be handled for agent interactions.
10
+ #
11
+ class SecurityScheme < A2A::Types::BaseModel
12
+ attr_reader :type
13
+
14
+ ##
15
+ # Create a security scheme from a hash (factory method)
16
+ #
17
+ # @param hash [Hash] The hash representation
18
+ # @return [SecurityScheme] The appropriate security scheme subclass instance
19
+ def self.from_h(hash)
20
+ return nil if hash.nil?
21
+
22
+ type = hash[:type] || hash["type"]
23
+ case type
24
+ when SECURITY_TYPE_API_KEY
25
+ ApiKeySecurityScheme.from_h(hash)
26
+ when SECURITY_TYPE_HTTP
27
+ HttpSecurityScheme.from_h(hash)
28
+ when SECURITY_TYPE_OAUTH2
29
+ OAuth2SecurityScheme.from_h(hash)
30
+ when SECURITY_TYPE_OPENID_CONNECT
31
+ OpenIdConnectSecurityScheme.from_h(hash)
32
+ when SECURITY_TYPE_MUTUAL_TLS
33
+ MutualTlsSecurityScheme.from_h(hash)
34
+ else
35
+ raise ArgumentError, "Unknown security scheme type: #{type}"
36
+ end
37
+ end
38
+
39
+ protected
40
+
41
+ def initialize(type:)
42
+ @type = type
43
+ validate!
44
+ end
45
+
46
+ private
47
+
48
+ def validate!
49
+ validate_required(:type)
50
+ validate_inclusion(:type, VALID_SECURITY_TYPES)
51
+ end
52
+ end
53
+
54
+ ##
55
+ # API Key security scheme
56
+ #
57
+ class ApiKeySecurityScheme < SecurityScheme
58
+ attr_reader :name, :location
59
+
60
+ ##
61
+ # Initialize a new API key security scheme
62
+ #
63
+ # @param name [String] The name of the API key parameter
64
+ # @param location [String] Where the API key is sent ("query", "header", "cookie")
65
+ def initialize(name:, location:)
66
+ @name = name
67
+ @location = location
68
+ super(type: SECURITY_TYPE_API_KEY)
69
+ end
70
+
71
+ private
72
+
73
+ def validate!
74
+ super
75
+ validate_required(:name, :location)
76
+ validate_inclusion(:location, %w[query header cookie])
77
+ end
78
+ end
79
+
80
+ ##
81
+ # HTTP security scheme (Basic, Bearer, etc.)
82
+ #
83
+ class HttpSecurityScheme < SecurityScheme
84
+ attr_reader :scheme, :bearer_format
85
+
86
+ ##
87
+ # Initialize a new HTTP security scheme
88
+ #
89
+ # @param scheme [String] The HTTP authentication scheme ("basic", "bearer", etc.)
90
+ # @param bearer_format [String, nil] Format of bearer token (e.g., "JWT")
91
+ def initialize(scheme:, bearer_format: nil)
92
+ @scheme = scheme
93
+ @bearer_format = bearer_format
94
+ super(type: SECURITY_TYPE_HTTP)
95
+ end
96
+
97
+ private
98
+
99
+ def validate!
100
+ super
101
+ validate_required(:scheme)
102
+ validate_inclusion(:scheme, %w[basic bearer digest])
103
+ end
104
+ end
105
+
106
+ ##
107
+ # OAuth 2.0 security scheme
108
+ #
109
+ class OAuth2SecurityScheme < SecurityScheme
110
+ attr_reader :flows, :scopes
111
+
112
+ ##
113
+ # Initialize a new OAuth 2.0 security scheme
114
+ #
115
+ # @param flows [Hash] OAuth 2.0 flows configuration
116
+ # @param scopes [Hash, nil] Available scopes
117
+ def initialize(flows:, scopes: nil)
118
+ @flows = flows
119
+ @scopes = scopes
120
+ super(type: SECURITY_TYPE_OAUTH2)
121
+ end
122
+
123
+ private
124
+
125
+ def validate!
126
+ super
127
+ validate_required(:flows)
128
+ validate_type(:flows, Hash)
129
+ end
130
+ end
131
+
132
+ ##
133
+ # OpenID Connect security scheme
134
+ #
135
+ class OpenIdConnectSecurityScheme < SecurityScheme
136
+ attr_reader :open_id_connect_url
137
+
138
+ ##
139
+ # Initialize a new OpenID Connect security scheme
140
+ #
141
+ # @param open_id_connect_url [String] The OpenID Connect discovery URL
142
+ def initialize(open_id_connect_url:)
143
+ @open_id_connect_url = open_id_connect_url
144
+ super(type: SECURITY_TYPE_OPENID_CONNECT)
145
+ end
146
+
147
+ private
148
+
149
+ def validate!
150
+ super
151
+ validate_required(:open_id_connect_url)
152
+ validate_type(:open_id_connect_url, String)
153
+ end
154
+ end
155
+
156
+ ##
157
+ # Mutual TLS security scheme
158
+ #
159
+ class MutualTlsSecurityScheme < SecurityScheme
160
+ ##
161
+ # Initialize a new mutual TLS security scheme
162
+ def initialize
163
+ super(type: SECURITY_TYPE_MUTUAL_TLS)
164
+ end
165
+ end
166
+ end
167
+ end