decision_agent 0.1.4 → 0.1.7

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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +83 -232
  3. data/bin/decision_agent +1 -1
  4. data/lib/decision_agent/ab_testing/ab_testing_agent.rb +46 -10
  5. data/lib/decision_agent/agent.rb +5 -3
  6. data/lib/decision_agent/auth/access_audit_logger.rb +122 -0
  7. data/lib/decision_agent/auth/authenticator.rb +127 -0
  8. data/lib/decision_agent/auth/password_reset_manager.rb +57 -0
  9. data/lib/decision_agent/auth/password_reset_token.rb +33 -0
  10. data/lib/decision_agent/auth/permission.rb +29 -0
  11. data/lib/decision_agent/auth/permission_checker.rb +43 -0
  12. data/lib/decision_agent/auth/rbac_adapter.rb +278 -0
  13. data/lib/decision_agent/auth/rbac_config.rb +51 -0
  14. data/lib/decision_agent/auth/role.rb +56 -0
  15. data/lib/decision_agent/auth/session.rb +33 -0
  16. data/lib/decision_agent/auth/session_manager.rb +57 -0
  17. data/lib/decision_agent/auth/user.rb +70 -0
  18. data/lib/decision_agent/context.rb +24 -4
  19. data/lib/decision_agent/decision.rb +10 -3
  20. data/lib/decision_agent/dsl/condition_evaluator.rb +378 -1
  21. data/lib/decision_agent/dsl/schema_validator.rb +8 -1
  22. data/lib/decision_agent/errors.rb +38 -0
  23. data/lib/decision_agent/evaluation.rb +10 -3
  24. data/lib/decision_agent/evaluation_validator.rb +8 -13
  25. data/lib/decision_agent/monitoring/dashboard_server.rb +1 -0
  26. data/lib/decision_agent/monitoring/metrics_collector.rb +17 -5
  27. data/lib/decision_agent/testing/batch_test_importer.rb +373 -0
  28. data/lib/decision_agent/testing/batch_test_runner.rb +244 -0
  29. data/lib/decision_agent/testing/test_coverage_analyzer.rb +191 -0
  30. data/lib/decision_agent/testing/test_result_comparator.rb +235 -0
  31. data/lib/decision_agent/testing/test_scenario.rb +42 -0
  32. data/lib/decision_agent/version.rb +10 -1
  33. data/lib/decision_agent/versioning/activerecord_adapter.rb +1 -1
  34. data/lib/decision_agent/versioning/file_storage_adapter.rb +96 -28
  35. data/lib/decision_agent/web/middleware/auth_middleware.rb +45 -0
  36. data/lib/decision_agent/web/middleware/permission_middleware.rb +94 -0
  37. data/lib/decision_agent/web/public/app.js +184 -29
  38. data/lib/decision_agent/web/public/batch_testing.html +640 -0
  39. data/lib/decision_agent/web/public/index.html +38 -10
  40. data/lib/decision_agent/web/public/login.html +298 -0
  41. data/lib/decision_agent/web/public/users.html +679 -0
  42. data/lib/decision_agent/web/server.rb +873 -7
  43. data/lib/decision_agent.rb +52 -0
  44. data/lib/generators/decision_agent/install/templates/README +1 -1
  45. data/lib/generators/decision_agent/install/templates/rule_version.rb +1 -1
  46. data/spec/ab_testing/ab_test_assignment_spec.rb +253 -0
  47. data/spec/ab_testing/ab_test_manager_spec.rb +282 -0
  48. data/spec/ab_testing/ab_testing_agent_spec.rb +481 -0
  49. data/spec/ab_testing/storage/adapter_spec.rb +64 -0
  50. data/spec/ab_testing/storage/memory_adapter_spec.rb +485 -0
  51. data/spec/advanced_operators_spec.rb +1003 -0
  52. data/spec/agent_spec.rb +40 -0
  53. data/spec/audit_adapters_spec.rb +18 -0
  54. data/spec/auth/access_audit_logger_spec.rb +394 -0
  55. data/spec/auth/authenticator_spec.rb +112 -0
  56. data/spec/auth/password_reset_spec.rb +294 -0
  57. data/spec/auth/permission_checker_spec.rb +207 -0
  58. data/spec/auth/permission_spec.rb +73 -0
  59. data/spec/auth/rbac_adapter_spec.rb +550 -0
  60. data/spec/auth/rbac_config_spec.rb +82 -0
  61. data/spec/auth/role_spec.rb +51 -0
  62. data/spec/auth/session_manager_spec.rb +172 -0
  63. data/spec/auth/session_spec.rb +112 -0
  64. data/spec/auth/user_spec.rb +130 -0
  65. data/spec/context_spec.rb +43 -0
  66. data/spec/decision_agent_spec.rb +96 -0
  67. data/spec/decision_spec.rb +423 -0
  68. data/spec/dsl/condition_evaluator_spec.rb +774 -0
  69. data/spec/evaluation_spec.rb +364 -0
  70. data/spec/evaluation_validator_spec.rb +165 -0
  71. data/spec/monitoring/metrics_collector_spec.rb +220 -2
  72. data/spec/monitoring/storage/activerecord_adapter_spec.rb +153 -1
  73. data/spec/monitoring/storage/base_adapter_spec.rb +61 -0
  74. data/spec/performance_optimizations_spec.rb +486 -0
  75. data/spec/spec_helper.rb +23 -0
  76. data/spec/testing/batch_test_importer_spec.rb +693 -0
  77. data/spec/testing/batch_test_runner_spec.rb +307 -0
  78. data/spec/testing/test_coverage_analyzer_spec.rb +292 -0
  79. data/spec/testing/test_result_comparator_spec.rb +392 -0
  80. data/spec/testing/test_scenario_spec.rb +113 -0
  81. data/spec/versioning/adapter_spec.rb +156 -0
  82. data/spec/versioning_spec.rb +253 -0
  83. data/spec/web/middleware/auth_middleware_spec.rb +133 -0
  84. data/spec/web/middleware/permission_middleware_spec.rb +247 -0
  85. data/spec/web_ui_rack_spec.rb +1705 -0
  86. metadata +103 -11
  87. data/spec/examples.txt +0 -612
@@ -0,0 +1,294 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe DecisionAgent::Auth::PasswordResetToken do
4
+ describe "#initialize" do
5
+ it "creates a token with user_id" do
6
+ token = DecisionAgent::Auth::PasswordResetToken.new(user_id: "user123")
7
+ expect(token.user_id).to eq("user123")
8
+ expect(token.token).to be_a(String)
9
+ expect(token.token.length).to eq(64) # 32 bytes hex = 64 chars
10
+ end
11
+
12
+ it "sets expiration time" do
13
+ token = DecisionAgent::Auth::PasswordResetToken.new(user_id: "user123", expires_in: 1800)
14
+ expect(token.expires_at).to be > Time.now.utc
15
+ expect(token.expires_at).to be <= Time.now.utc + 1801
16
+ end
17
+ end
18
+
19
+ describe "#expired?" do
20
+ it "returns false for valid token" do
21
+ token = DecisionAgent::Auth::PasswordResetToken.new(user_id: "user123", expires_in: 3600)
22
+ expect(token.expired?).to be false
23
+ end
24
+
25
+ it "returns true for expired token" do
26
+ token = DecisionAgent::Auth::PasswordResetToken.new(user_id: "user123", expires_in: -1)
27
+ expect(token.expired?).to be true
28
+ end
29
+ end
30
+
31
+ describe "#valid?" do
32
+ it "returns true for non-expired token" do
33
+ token = DecisionAgent::Auth::PasswordResetToken.new(user_id: "user123", expires_in: 3600)
34
+ expect(token.valid?).to be true
35
+ end
36
+
37
+ it "returns false for expired token" do
38
+ token = DecisionAgent::Auth::PasswordResetToken.new(user_id: "user123", expires_in: -1)
39
+ expect(token.valid?).to be false
40
+ end
41
+ end
42
+ end
43
+
44
+ RSpec.describe DecisionAgent::Auth::PasswordResetManager do
45
+ let(:manager) { DecisionAgent::Auth::PasswordResetManager.new }
46
+
47
+ describe "#create_token" do
48
+ it "creates a new reset token" do
49
+ token = manager.create_token("user123")
50
+ expect(token).to be_a(DecisionAgent::Auth::PasswordResetToken)
51
+ expect(token.user_id).to eq("user123")
52
+ end
53
+
54
+ it "stores the token" do
55
+ token = manager.create_token("user123")
56
+ retrieved = manager.get_token(token.token)
57
+ expect(retrieved).to eq(token)
58
+ end
59
+ end
60
+
61
+ describe "#get_token" do
62
+ it "returns token for valid token string" do
63
+ token = manager.create_token("user123")
64
+ retrieved = manager.get_token(token.token)
65
+ expect(retrieved).to eq(token)
66
+ end
67
+
68
+ it "returns nil for invalid token" do
69
+ expect(manager.get_token("invalid_token")).to be_nil
70
+ end
71
+
72
+ it "returns nil for expired token" do
73
+ token = manager.create_token("user123", expires_in: -1)
74
+ expect(manager.get_token(token.token)).to be_nil
75
+ end
76
+ end
77
+
78
+ describe "#delete_token" do
79
+ it "deletes a token" do
80
+ token = manager.create_token("user123")
81
+ manager.delete_token(token.token)
82
+ expect(manager.get_token(token.token)).to be_nil
83
+ end
84
+ end
85
+
86
+ describe "#delete_user_tokens" do
87
+ it "deletes all tokens for a user" do
88
+ token1 = manager.create_token("user123")
89
+ token2 = manager.create_token("user123")
90
+ token3 = manager.create_token("user456")
91
+
92
+ manager.delete_user_tokens("user123")
93
+
94
+ expect(manager.get_token(token1.token)).to be_nil
95
+ expect(manager.get_token(token2.token)).to be_nil
96
+ expect(manager.get_token(token3.token)).to eq(token3) # Other user's token still exists
97
+ end
98
+ end
99
+
100
+ describe "#count" do
101
+ it "returns zero initially" do
102
+ expect(manager.count).to eq(0)
103
+ end
104
+
105
+ it "returns correct count after creating tokens" do
106
+ manager.create_token("user123")
107
+ expect(manager.count).to eq(1)
108
+
109
+ manager.create_token("user123")
110
+ expect(manager.count).to eq(2)
111
+
112
+ manager.create_token("user456")
113
+ expect(manager.count).to eq(3)
114
+ end
115
+
116
+ it "reflects deletions" do
117
+ token1 = manager.create_token("user123")
118
+ manager.create_token("user123")
119
+ expect(manager.count).to eq(2)
120
+
121
+ manager.delete_token(token1.token)
122
+ expect(manager.count).to eq(1)
123
+
124
+ manager.delete_user_tokens("user123")
125
+ expect(manager.count).to eq(0)
126
+ end
127
+ end
128
+
129
+ describe "#cleanup_expired_tokens" do
130
+ it "removes expired tokens" do
131
+ # Create expired token
132
+ expired_token = manager.create_token("user123", expires_in: -1)
133
+ # Create valid token
134
+ valid_token = manager.create_token("user456", expires_in: 3600)
135
+
136
+ expect(manager.count).to eq(2)
137
+
138
+ # Force cleanup by calling it directly (it's called during create_token, but we can test it)
139
+ # We'll create another token to trigger cleanup
140
+ manager.create_token("user789", expires_in: 3600)
141
+
142
+ # Expired token should be cleaned up
143
+ expect(manager.get_token(expired_token.token)).to be_nil
144
+ expect(manager.get_token(valid_token.token)).to eq(valid_token)
145
+ end
146
+
147
+ it "only runs cleanup after cleanup_interval" do
148
+ manager = DecisionAgent::Auth::PasswordResetManager.new
149
+
150
+ # Create an expired token
151
+ expired_token = manager.create_token("user123", expires_in: -1)
152
+ expect(manager.count).to eq(1)
153
+
154
+ # Create another token immediately - cleanup should not run yet if interval not passed
155
+ # But since we use -1 expires_in, the token is already expired, so get_token will return nil
156
+ # The cleanup_expired_tokens is called during create_token, but it checks the interval
157
+ # Let's test by manually setting last_cleanup to far in the past
158
+ manager.instance_variable_set(:@last_cleanup, Time.now - 400) # More than 300 seconds
159
+ manager.create_token("user456", expires_in: 3600)
160
+
161
+ # The expired token should be cleaned up now
162
+ expect(manager.get_token(expired_token.token)).to be_nil
163
+ end
164
+ end
165
+ end
166
+
167
+ RSpec.describe DecisionAgent::Auth::Authenticator do
168
+ let(:authenticator) { DecisionAgent::Auth::Authenticator.new }
169
+
170
+ describe "#request_password_reset" do
171
+ before do
172
+ authenticator.create_user(
173
+ email: "test@example.com",
174
+ password: "password123"
175
+ )
176
+ end
177
+
178
+ it "returns a token for valid user" do
179
+ token = authenticator.request_password_reset("test@example.com")
180
+ expect(token).to be_a(DecisionAgent::Auth::PasswordResetToken)
181
+ expect(token.user_id).to be_a(String)
182
+ end
183
+
184
+ it "returns nil for non-existent user" do
185
+ token = authenticator.request_password_reset("nonexistent@example.com")
186
+ expect(token).to be_nil
187
+ end
188
+
189
+ it "returns nil for inactive user" do
190
+ user = authenticator.find_user_by_email("test@example.com")
191
+ user.active = false
192
+
193
+ token = authenticator.request_password_reset("test@example.com")
194
+ expect(token).to be_nil
195
+ end
196
+
197
+ it "deletes existing tokens when creating new one" do
198
+ token1 = authenticator.request_password_reset("test@example.com")
199
+ token2 = authenticator.request_password_reset("test@example.com")
200
+
201
+ expect(authenticator.password_reset_manager.get_token(token1.token)).to be_nil
202
+ expect(authenticator.password_reset_manager.get_token(token2.token)).to eq(token2)
203
+ end
204
+ end
205
+
206
+ describe "#reset_password" do
207
+ before do
208
+ authenticator.create_user(
209
+ email: "test@example.com",
210
+ password: "oldpassword"
211
+ )
212
+ end
213
+
214
+ it "resets password with valid token" do
215
+ token = authenticator.request_password_reset("test@example.com")
216
+ user = authenticator.reset_password(token.token, "newpassword123")
217
+
218
+ expect(user).to be_a(DecisionAgent::Auth::User)
219
+ expect(user.authenticate("newpassword123")).to be true
220
+ expect(user.authenticate("oldpassword")).to be false
221
+ end
222
+
223
+ it "returns nil for invalid token" do
224
+ user = authenticator.reset_password("invalid_token", "newpassword123")
225
+ expect(user).to be_nil
226
+ end
227
+
228
+ it "returns nil for expired token" do
229
+ token = authenticator.request_password_reset("test@example.com")
230
+ # Manually expire the token
231
+ token.instance_variable_set(:@expires_at, Time.now.utc - 1)
232
+
233
+ user = authenticator.reset_password(token.token, "newpassword123")
234
+ expect(user).to be_nil
235
+ end
236
+
237
+ it "invalidates all user sessions after password reset" do
238
+ session1 = authenticator.login("test@example.com", "oldpassword")
239
+ session2 = authenticator.login("test@example.com", "oldpassword")
240
+
241
+ token = authenticator.request_password_reset("test@example.com")
242
+ authenticator.reset_password(token.token, "newpassword123")
243
+
244
+ expect(authenticator.authenticate(session1.token)).to be_nil
245
+ expect(authenticator.authenticate(session2.token)).to be_nil
246
+ end
247
+
248
+ it "deletes the token after use" do
249
+ token = authenticator.request_password_reset("test@example.com")
250
+ authenticator.reset_password(token.token, "newpassword123")
251
+
252
+ expect(authenticator.password_reset_manager.get_token(token.token)).to be_nil
253
+ end
254
+
255
+ it "deletes all tokens for user after reset" do
256
+ token1 = authenticator.request_password_reset("test@example.com")
257
+ token2 = authenticator.request_password_reset("test@example.com")
258
+
259
+ authenticator.reset_password(token2.token, "newpassword123")
260
+
261
+ expect(authenticator.password_reset_manager.get_token(token1.token)).to be_nil
262
+ expect(authenticator.password_reset_manager.get_token(token2.token)).to be_nil
263
+ end
264
+ end
265
+ end
266
+
267
+ RSpec.describe DecisionAgent::Auth::User do
268
+ describe "#update_password" do
269
+ it "updates the password" do
270
+ user = DecisionAgent::Auth::User.new(
271
+ email: "test@example.com",
272
+ password: "oldpassword"
273
+ )
274
+
275
+ user.update_password("newpassword123")
276
+
277
+ expect(user.authenticate("newpassword123")).to be true
278
+ expect(user.authenticate("oldpassword")).to be false
279
+ end
280
+
281
+ it "updates the updated_at timestamp" do
282
+ user = DecisionAgent::Auth::User.new(
283
+ email: "test@example.com",
284
+ password: "oldpassword"
285
+ )
286
+
287
+ original_updated_at = user.updated_at
288
+ sleep(0.01) # Small delay to ensure timestamp difference
289
+ user.update_password("newpassword123")
290
+
291
+ expect(user.updated_at).to be > original_updated_at
292
+ end
293
+ end
294
+ end
@@ -0,0 +1,207 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe DecisionAgent::Auth::PermissionChecker do
4
+ let(:checker) { DecisionAgent::Auth::PermissionChecker.new }
5
+
6
+ describe "#can?" do
7
+ let(:admin_user) do
8
+ DecisionAgent::Auth::User.new(
9
+ email: "admin@example.com",
10
+ password: "password123",
11
+ roles: [:admin]
12
+ )
13
+ end
14
+
15
+ let(:editor_user) do
16
+ DecisionAgent::Auth::User.new(
17
+ email: "editor@example.com",
18
+ password: "password123",
19
+ roles: [:editor]
20
+ )
21
+ end
22
+
23
+ let(:viewer_user) do
24
+ DecisionAgent::Auth::User.new(
25
+ email: "viewer@example.com",
26
+ password: "password123",
27
+ roles: [:viewer]
28
+ )
29
+ end
30
+
31
+ it "returns true if user has permission" do
32
+ expect(checker.can?(admin_user, :write)).to be true
33
+ expect(checker.can?(editor_user, :write)).to be true
34
+ expect(checker.can?(viewer_user, :read)).to be true
35
+ end
36
+
37
+ it "returns false if user lacks permission" do
38
+ expect(checker.can?(viewer_user, :write)).to be false
39
+ expect(checker.can?(editor_user, :delete)).to be false
40
+ end
41
+
42
+ it "returns false for nil user" do
43
+ expect(checker.can?(nil, :read)).to be false
44
+ end
45
+
46
+ it "returns false for inactive user" do
47
+ admin_user.active = false
48
+ expect(checker.can?(admin_user, :read)).to be false
49
+ end
50
+ end
51
+
52
+ describe "#require_permission!" do
53
+ let(:user) do
54
+ DecisionAgent::Auth::User.new(
55
+ email: "user@example.com",
56
+ password: "password123",
57
+ roles: [:viewer]
58
+ )
59
+ end
60
+
61
+ it "does not raise if user has permission" do
62
+ expect do
63
+ checker.require_permission!(user, :read)
64
+ end.not_to raise_error
65
+ end
66
+
67
+ it "raises PermissionDeniedError if user lacks permission" do
68
+ expect do
69
+ checker.require_permission!(user, :write)
70
+ end.to raise_error(DecisionAgent::PermissionDeniedError)
71
+ end
72
+ end
73
+
74
+ describe "#has_role?" do
75
+ let(:user) do
76
+ DecisionAgent::Auth::User.new(
77
+ email: "user@example.com",
78
+ password: "password123",
79
+ roles: [:editor]
80
+ )
81
+ end
82
+
83
+ it "returns true if user has role" do
84
+ expect(checker.has_role?(user, :editor)).to be true
85
+ end
86
+
87
+ it "returns false if user lacks role" do
88
+ expect(checker.has_role?(user, :admin)).to be false
89
+ end
90
+
91
+ it "returns false for nil user" do
92
+ expect(checker.has_role?(nil, :editor)).to be false
93
+ end
94
+ end
95
+
96
+ describe "#require_role!" do
97
+ let(:user) do
98
+ DecisionAgent::Auth::User.new(
99
+ email: "user@example.com",
100
+ password: "password123",
101
+ roles: [:editor]
102
+ )
103
+ end
104
+
105
+ it "does not raise if user has role" do
106
+ expect do
107
+ checker.require_role!(user, :editor)
108
+ end.not_to raise_error
109
+ end
110
+
111
+ it "returns true if user has role" do
112
+ result = checker.require_role!(user, :editor)
113
+ expect(result).to be true
114
+ end
115
+
116
+ it "raises PermissionDeniedError if user lacks role" do
117
+ expect do
118
+ checker.require_role!(user, :admin)
119
+ end.to raise_error(DecisionAgent::PermissionDeniedError, /User does not have role: admin/)
120
+ end
121
+ end
122
+
123
+ describe "#active?" do
124
+ let(:user) do
125
+ DecisionAgent::Auth::User.new(
126
+ email: "user@example.com",
127
+ password: "password123"
128
+ )
129
+ end
130
+
131
+ it "returns true for active user" do
132
+ user.active = true
133
+ expect(checker.active?(user)).to be true
134
+ end
135
+
136
+ it "returns false for inactive user" do
137
+ user.active = false
138
+ expect(checker.active?(user)).to be false
139
+ end
140
+
141
+ it "returns true for user without active attribute" do
142
+ user = double("User", id: "123", email: "test@example.com")
143
+ expect(checker.active?(user)).to be true
144
+ end
145
+
146
+ it "returns false for nil user" do
147
+ expect(checker.active?(nil)).to be false
148
+ end
149
+ end
150
+
151
+ describe "#user_id" do
152
+ let(:user) do
153
+ DecisionAgent::Auth::User.new(
154
+ email: "user@example.com",
155
+ password: "password123"
156
+ )
157
+ end
158
+
159
+ it "returns user id" do
160
+ expect(checker.user_id(user)).to eq(user.id)
161
+ end
162
+
163
+ it "returns nil for nil user" do
164
+ expect(checker.user_id(nil)).to be_nil
165
+ end
166
+
167
+ it "handles user without id method" do
168
+ user = double("User", to_s: "user_string")
169
+ expect(checker.user_id(user)).to eq("user_string")
170
+ end
171
+ end
172
+
173
+ describe "#user_email" do
174
+ let(:user) do
175
+ DecisionAgent::Auth::User.new(
176
+ email: "user@example.com",
177
+ password: "password123"
178
+ )
179
+ end
180
+
181
+ it "returns user email" do
182
+ expect(checker.user_email(user)).to eq("user@example.com")
183
+ end
184
+
185
+ it "returns nil for nil user" do
186
+ expect(checker.user_email(nil)).to be_nil
187
+ end
188
+
189
+ it "returns nil for user without email method" do
190
+ user = double("User", id: "123")
191
+ expect(checker.user_email(user)).to be_nil
192
+ end
193
+ end
194
+
195
+ describe "#adapter" do
196
+ it "uses default adapter when none provided" do
197
+ checker = DecisionAgent::Auth::PermissionChecker.new
198
+ expect(checker.adapter).to be_a(DecisionAgent::Auth::DefaultAdapter)
199
+ end
200
+
201
+ it "uses provided adapter" do
202
+ custom_adapter = DecisionAgent::Auth::DefaultAdapter.new
203
+ checker = DecisionAgent::Auth::PermissionChecker.new(adapter: custom_adapter)
204
+ expect(checker.adapter).to eq(custom_adapter)
205
+ end
206
+ end
207
+ end
@@ -0,0 +1,73 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe DecisionAgent::Auth::Permission do
4
+ describe ".all" do
5
+ it "returns all permission symbols" do
6
+ permissions = DecisionAgent::Auth::Permission.all
7
+ expect(permissions).to be_an(Array)
8
+ expect(permissions).to include(:read, :write, :delete, :approve, :deploy, :manage_users, :audit)
9
+ end
10
+
11
+ it "returns only symbol keys" do
12
+ permissions = DecisionAgent::Auth::Permission.all
13
+ expect(permissions.all? { |p| p.is_a?(Symbol) }).to be true
14
+ end
15
+ end
16
+
17
+ describe ".exists?" do
18
+ it "returns true for valid permissions" do
19
+ expect(DecisionAgent::Auth::Permission.exists?(:read)).to be true
20
+ expect(DecisionAgent::Auth::Permission.exists?(:write)).to be true
21
+ expect(DecisionAgent::Auth::Permission.exists?(:delete)).to be true
22
+ expect(DecisionAgent::Auth::Permission.exists?(:approve)).to be true
23
+ expect(DecisionAgent::Auth::Permission.exists?(:deploy)).to be true
24
+ expect(DecisionAgent::Auth::Permission.exists?(:manage_users)).to be true
25
+ expect(DecisionAgent::Auth::Permission.exists?(:audit)).to be true
26
+ end
27
+
28
+ it "converts string to symbol" do
29
+ expect(DecisionAgent::Auth::Permission.exists?("read")).to be true
30
+ expect(DecisionAgent::Auth::Permission.exists?("write")).to be true
31
+ end
32
+
33
+ it "returns false for invalid permissions" do
34
+ expect(DecisionAgent::Auth::Permission.exists?(:invalid)).to be false
35
+ expect(DecisionAgent::Auth::Permission.exists?("invalid")).to be false
36
+ expect(DecisionAgent::Auth::Permission.exists?(:unknown)).to be false
37
+ end
38
+
39
+ it "raises error for nil (not handled)" do
40
+ expect do
41
+ DecisionAgent::Auth::Permission.exists?(nil)
42
+ end.to raise_error(NoMethodError)
43
+ end
44
+ end
45
+
46
+ describe ".description_for" do
47
+ it "returns description for valid permissions" do
48
+ expect(DecisionAgent::Auth::Permission.description_for(:read)).to eq("Read access to rules and versions")
49
+ expect(DecisionAgent::Auth::Permission.description_for(:write)).to eq("Create and modify rules")
50
+ expect(DecisionAgent::Auth::Permission.description_for(:delete)).to eq("Delete rules and versions")
51
+ expect(DecisionAgent::Auth::Permission.description_for(:approve)).to eq("Approve rule changes")
52
+ expect(DecisionAgent::Auth::Permission.description_for(:deploy)).to eq("Deploy rule versions")
53
+ expect(DecisionAgent::Auth::Permission.description_for(:manage_users)).to eq("Manage users and roles")
54
+ expect(DecisionAgent::Auth::Permission.description_for(:audit)).to eq("Access audit logs")
55
+ end
56
+
57
+ it "converts string to symbol" do
58
+ expect(DecisionAgent::Auth::Permission.description_for("read")).to eq("Read access to rules and versions")
59
+ expect(DecisionAgent::Auth::Permission.description_for("write")).to eq("Create and modify rules")
60
+ end
61
+
62
+ it "returns nil for invalid permissions" do
63
+ expect(DecisionAgent::Auth::Permission.description_for(:invalid)).to be_nil
64
+ expect(DecisionAgent::Auth::Permission.description_for("invalid")).to be_nil
65
+ end
66
+
67
+ it "raises error for nil (not handled)" do
68
+ expect do
69
+ DecisionAgent::Auth::Permission.description_for(nil)
70
+ end.to raise_error(NoMethodError)
71
+ end
72
+ end
73
+ end