anzen 0.1.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.
data/bin/console ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'anzen'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ require 'irb'
11
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,608 @@
1
+ # Anzen Ruby API Reference
2
+
3
+ This document provides comprehensive API reference for the Anzen runtime safety protection gem.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Core Module](#core-module)
8
+ - [Configuration](#configuration)
9
+ - [Monitors](#monitors)
10
+ - [Exceptions](#exceptions)
11
+ - [CLI Interface](#cli-interface)
12
+
13
+ ## Core Module
14
+
15
+ The `Anzen` module provides the main public API for runtime safety protection.
16
+
17
+ ### Setup and Initialization
18
+
19
+ #### `Anzen.setup(config: {})`
20
+
21
+ Initializes the Anzen safety protection system with the specified configuration.
22
+
23
+ **Parameters:**
24
+ - `config` (Hash): Configuration hash with the following structure:
25
+ - `enabled_monitors` (Array<String>): Array of monitor names to enable initially
26
+ - `monitors` (Hash): Monitor-specific configuration
27
+
28
+ **Example:**
29
+ ```ruby
30
+ Anzen.setup(config: {
31
+ enabled_monitors: ['recursion', 'memory'],
32
+ monitors: {
33
+ recursion: { depth_limit: 1000 },
34
+ memory: { limit_mb: 512, sampling_interval_ms: 100 }
35
+ }
36
+ })
37
+ ```
38
+
39
+ **Raises:**
40
+ - `Anzen::InitializationError`: If Anzen is already initialized
41
+ - `Anzen::ConfigurationError`: If configuration is invalid
42
+
43
+ **Returns:** `nil`
44
+
45
+ ### Runtime Control
46
+
47
+ #### `Anzen.enable(name)`
48
+
49
+ Enables a registered monitor by name.
50
+
51
+ **Parameters:**
52
+ - `name` (String): Name of the monitor to enable
53
+
54
+ **Example:**
55
+ ```ruby
56
+ Anzen.enable('recursion')
57
+ Anzen.enable('memory')
58
+ ```
59
+
60
+ **Raises:**
61
+ - `Anzen::MonitorNotFoundError`: If monitor is not registered
62
+
63
+ **Returns:** `true` if enabled, `false` if already enabled
64
+
65
+ #### `Anzen.disable(name)`
66
+
67
+ Disables a registered monitor by name.
68
+
69
+ **Parameters:**
70
+ - `name` (String): Name of the monitor to disable
71
+
72
+ **Example:**
73
+ ```ruby
74
+ Anzen.disable('memory')
75
+ ```
76
+
77
+ **Raises:**
78
+ - `Anzen::MonitorNotFoundError`: If monitor is not registered
79
+
80
+ **Returns:** `true` if disabled, `false` if already disabled
81
+
82
+ #### `Anzen.check!`
83
+
84
+ Performs safety checks on all enabled monitors. Raises the first violation detected.
85
+
86
+ **Example:**
87
+ ```ruby
88
+ begin
89
+ Anzen.check!
90
+ puts "All checks passed"
91
+ rescue Anzen::RecursionLimitExceeded => e
92
+ puts "Recursion violation: #{e.current_depth} > #{e.threshold}"
93
+ rescue Anzen::MemoryLimitExceeded => e
94
+ puts "Memory violation: #{e.current_memory_mb}MB > #{e.memory_limit_mb}MB"
95
+ end
96
+ ```
97
+
98
+ **Raises:**
99
+ - `Anzen::ViolationError`: Subclass for safety violations
100
+ - `Anzen::CheckFailedError`: For infrastructure errors
101
+
102
+ **Returns:** `nil` if all checks pass
103
+
104
+ ### Status and Information
105
+
106
+ #### `Anzen.status`
107
+
108
+ Returns the current status of all monitors and the system.
109
+
110
+ **Returns:** Hash with the following structure:
111
+ ```ruby
112
+ {
113
+ enabled_monitors: ['recursion', 'memory'],
114
+ setup_time: Time, # When Anzen was initialized
115
+ monitors: {
116
+ 'recursion' => {
117
+ status: 'enabled', # or 'disabled'
118
+ thresholds: { depth_limit: 1000 },
119
+ last_check: Time, # or nil
120
+ violations_detected: 0
121
+ },
122
+ 'memory' => {
123
+ status: 'enabled',
124
+ thresholds: { limit_mb: 512, sampling_interval_ms: 100 },
125
+ last_check: Time,
126
+ violations_detected: 0
127
+ }
128
+ }
129
+ }
130
+ ```
131
+
132
+ **Example:**
133
+ ```ruby
134
+ status = Anzen.status
135
+ puts "Enabled monitors: #{status[:enabled_monitors].join(', ')}"
136
+ puts "Setup time: #{status[:setup_time]}"
137
+ ```
138
+
139
+ ### Custom Monitor Registration
140
+
141
+ #### `Anzen.register_monitor(monitor_instance)`
142
+
143
+ Registers a custom monitor instance with the system.
144
+
145
+ **Parameters:**
146
+ - `monitor_instance`: Object implementing the Monitor interface
147
+
148
+ **Example:**
149
+ ```ruby
150
+ class CustomMonitor
151
+ def name; 'custom'; end
152
+ def enable; @enabled = true; end
153
+ def disable; @enabled = false; end
154
+ def enabled?; @enabled; end
155
+ def check!; # custom safety check; end
156
+ def status; { status: enabled? ? 'enabled' : 'disabled' }; end
157
+ def to_cli; "Custom monitor: #{enabled? ? 'enabled' : 'disabled'}"; end
158
+ end
159
+
160
+ Anzen.register_monitor(CustomMonitor.new)
161
+ ```
162
+
163
+ **Raises:**
164
+ - `Anzen::InvalidMonitorError`: If monitor doesn't implement required interface
165
+ - `Anzen::MonitorNameConflictError`: If monitor name already registered
166
+
167
+ **Returns:** `true` if registered successfully
168
+
169
+ ## Configuration
170
+
171
+ Configuration can be loaded from multiple sources with the following precedence (highest to lowest):
172
+
173
+ 1. Programmatic configuration (passed to `Anzen.setup`)
174
+ 2. Environment variable `ANZEN_CONFIG` (JSON/YAML)
175
+ 3. Configuration file (anzen.yml, anzen.json)
176
+
177
+ ### Configuration Schema
178
+
179
+ ```yaml
180
+ anzen:
181
+ enabled_monitors:
182
+ - recursion
183
+ - memory
184
+ monitors:
185
+ recursion:
186
+ depth_limit: 1000
187
+ memory:
188
+ limit_mb: 512
189
+ sampling_interval_ms: 100
190
+ ```
191
+
192
+ ### Environment Variable Configuration
193
+
194
+ ```bash
195
+ export ANZEN_CONFIG='{
196
+ "enabled_monitors": ["recursion", "memory"],
197
+ "monitors": {
198
+ "recursion": {"depth_limit": 500},
199
+ "memory": {"limit_mb": 1024}
200
+ }
201
+ }'
202
+ ```
203
+
204
+ ### File-based Configuration
205
+
206
+ Create `anzen.yml` or `anzen.json` in your project root:
207
+
208
+ ```yaml
209
+ # anzen.yml
210
+ anzen:
211
+ enabled_monitors: [recursion, memory]
212
+ monitors:
213
+ recursion:
214
+ depth_limit: 1000
215
+ memory:
216
+ limit_mb: 512
217
+ ```
218
+
219
+ ## Monitors
220
+
221
+ Anzen includes built-in monitors for common safety concerns. All monitors implement the same interface.
222
+
223
+ ### Monitor Interface
224
+
225
+ All monitors must implement these methods:
226
+
227
+ - `name` (String): Unique monitor identifier
228
+ - `enable`: Enable the monitor
229
+ - `disable`: Disable the monitor
230
+ - `enabled?` (Boolean): Check if monitor is enabled
231
+ - `check!`: Perform safety check, raise ViolationError if unsafe
232
+ - `status` (Hash): Return monitor status information
233
+ - `to_cli` (String): Return human-readable status for CLI
234
+
235
+ ### Built-in Monitors
236
+
237
+ #### RecursionMonitor
238
+
239
+ Detects recursive method calls and raises immediately on first detection.
240
+
241
+ **Configuration:**
242
+ - No thresholds - blocks all recursion
243
+
244
+ **Status Fields:**
245
+ - `status`: 'enabled' or 'disabled'
246
+ - `violations_detected`: Number of recursion violations detected
247
+
248
+ #### CallStackDepthMonitor
249
+
250
+ Limits call stack depth to prevent stack overflow.
251
+
252
+ **Configuration:**
253
+ - `depth_limit` (Integer): Maximum allowed stack depth (default: 1000)
254
+
255
+ **Status Fields:**
256
+ - `status`: 'enabled' or 'disabled'
257
+ - `thresholds`: { depth_limit: Integer }
258
+ - `last_check`: Time of last check or nil
259
+ - `violations_detected`: Number of depth violations
260
+
261
+ #### MemoryMonitor
262
+
263
+ Monitors process memory usage with sampling to prevent OOM conditions.
264
+
265
+ **Configuration:**
266
+ - `limit_mb` (Integer): Memory limit in MB
267
+ - `sampling_interval_ms` (Integer): Minimum time between checks (default: 100)
268
+
269
+ **Status Fields:**
270
+ - `status`: 'enabled' or 'disabled'
271
+ - `thresholds`: { limit_mb: Integer, sampling_interval_ms: Integer }
272
+ - `last_check`: Time of last check or nil
273
+ - `violations_detected`: Number of memory violations
274
+
275
+ ## Exceptions
276
+
277
+ Anzen uses a structured exception hierarchy for different types of errors.
278
+
279
+ ### Violation Errors
280
+
281
+ Raised when safety violations are detected during `check!` calls.
282
+
283
+ #### `Anzen::ViolationError`
284
+
285
+ Base class for all safety violations. Inherits from `StandardError`.
286
+
287
+ **Attributes:**
288
+ - `monitor_name` (String): Name of the monitor that detected the violation
289
+
290
+ #### `Anzen::RecursionLimitExceeded`
291
+
292
+ Raised when recursion limits are exceeded.
293
+
294
+ **Attributes:**
295
+ - `current_depth` (Integer): Current call stack depth
296
+ - `threshold` (Integer): Configured depth limit
297
+
298
+ **Example:**
299
+ ```ruby
300
+ rescue Anzen::RecursionLimitExceeded => e
301
+ puts "Recursion limit exceeded: #{e.current_depth} > #{e.threshold}"
302
+ end
303
+ ```
304
+
305
+ #### `Anzen::MemoryLimitExceeded`
306
+
307
+ Raised when memory limits are exceeded.
308
+
309
+ **Attributes:**
310
+ - `current_memory_mb` (Float): Current memory usage in MB
311
+ - `memory_limit_mb` (Integer): Configured memory limit in MB
312
+
313
+ **Example:**
314
+ ```ruby
315
+ rescue Anzen::MemoryLimitExceeded => e
316
+ puts "Memory limit exceeded: #{e.current_memory_mb}MB > #{e.memory_limit_mb}MB"
317
+ end
318
+ ```
319
+
320
+ ### Infrastructure Errors
321
+
322
+ Raised for configuration and operational issues.
323
+
324
+ #### `Anzen::CheckFailedError`
325
+
326
+ Raised when a monitor check fails due to infrastructure issues.
327
+
328
+ **Attributes:**
329
+ - `monitor_name` (String): Name of the monitor that failed
330
+ - `reason` (String): Description of the failure
331
+ - `original_error` (Exception): The underlying error that caused the failure
332
+
333
+ #### `Anzen::ConfigurationError`
334
+
335
+ Raised when configuration is invalid.
336
+
337
+ **Attributes:**
338
+ - `field` (String): Configuration field that is invalid
339
+ - `value`: The invalid value
340
+ - `reason` (String): Why the value is invalid
341
+
342
+ #### `Anzen::MonitorNotFoundError`
343
+
344
+ Raised when trying to enable/disable a monitor that doesn't exist.
345
+
346
+ **Attributes:**
347
+ - `monitor_name` (String): Name of the monitor that was not found
348
+
349
+ #### `Anzen::InvalidMonitorError`
350
+
351
+ Raised when registering a monitor that doesn't implement the required interface.
352
+
353
+ **Attributes:**
354
+ - `monitor_class`: The invalid monitor class
355
+ - `missing_methods` (Array<String>): Methods that are missing from the interface
356
+
357
+ #### `Anzen::MonitorNameConflictError`
358
+
359
+ Raised when trying to register a monitor with a name that already exists.
360
+
361
+ **Attributes:**
362
+ - `monitor_name` (String): The conflicting monitor name
363
+
364
+ #### `Anzen::InitializationError`
365
+
366
+ Raised when trying to initialize Anzen multiple times.
367
+
368
+ **Attributes:**
369
+ - `reason` (String): Why initialization failed
370
+
371
+ ## CLI Interface
372
+
373
+ The Anzen CLI provides command-line access to system status and configuration.
374
+
375
+ ### Commands
376
+
377
+ #### `anzen status [--format json|text]`
378
+
379
+ Displays the current status of all monitors and the system.
380
+
381
+ **Options:**
382
+ - `--format`: Output format ('json' or 'text', default: 'text')
383
+
384
+ **Exit Codes:**
385
+ - 0: Success
386
+ - 1: General error
387
+ - 2: Monitor not found
388
+ - 3: Configuration error
389
+ - 4: Initialization error
390
+
391
+ **Example Output (text):**
392
+ ```
393
+ Anzen Safety Protection Status
394
+ ========================================
395
+
396
+ Enabled Monitors: recursion, memory
397
+
398
+ Monitor: recursion
399
+ Status: enabled
400
+ Thresholds:
401
+ depth_limit: 1000
402
+ Last Check: never
403
+ Violations Detected: 0
404
+
405
+ Monitor: memory
406
+ Status: enabled
407
+ Thresholds:
408
+ limit_mb: 512
409
+ sampling_interval_ms: 100
410
+ Last Check: never
411
+ Violations Detected: 0
412
+
413
+ Total Violations: 0
414
+ Setup Time: 2025-11-17 17:05:02 EST
415
+ ```
416
+
417
+ #### `anzen config [monitor_name] [--format json|text]`
418
+
419
+ Displays configuration information.
420
+
421
+ **Parameters:**
422
+ - `monitor_name` (optional): Show config for specific monitor only
423
+
424
+ **Options:**
425
+ - `--format`: Output format ('json' or 'text', default: 'text')
426
+
427
+ **Example:**
428
+ ```bash
429
+ anzen config memory
430
+ anzen config --format json
431
+ ```
432
+
433
+ #### `anzen info [--format json|text]`
434
+
435
+ Displays system and gem information.
436
+
437
+ **Options:**
438
+ - `--format`: Output format ('json' or 'text', default: 'text')
439
+
440
+ **Example Output:**
441
+ ```
442
+ Anzen Runtime Safety Protection
443
+ Version: 0.1.0
444
+ Ruby Version: 3.2.2
445
+ Platform: x86_64-darwin22
446
+ Process ID: 12345
447
+ Memory Usage: 45.2 MB
448
+ ```
449
+
450
+ #### `anzen help [command]`
451
+
452
+ Displays help information.
453
+
454
+ **Parameters:**
455
+ - `command` (optional): Show help for specific command
456
+
457
+ **Example:**
458
+ ```bash
459
+ anzen help
460
+ anzen help status
461
+ ```
462
+
463
+ ### Global Options
464
+
465
+ - `--version`: Show version information
466
+ - `--help`: Show help information
467
+
468
+ ### Exit Codes
469
+
470
+ All CLI commands return standardized exit codes:
471
+
472
+ - `0`: Success
473
+ - `1`: General error (unexpected exceptions)
474
+ - `2`: Monitor not found
475
+ - `3`: Configuration error
476
+ - `4`: Initialization error (Anzen not set up)
477
+
478
+ ## Integration Patterns
479
+
480
+ ### Rails Application
481
+
482
+ ```ruby
483
+ # config/initializers/anzen.rb
484
+ require 'anzen'
485
+
486
+ Anzen.setup(config: {
487
+ enabled_monitors: ['recursion', 'memory'],
488
+ monitors: {
489
+ recursion: { depth_limit: 1000 },
490
+ memory: { limit_mb: 512 }
491
+ }
492
+ })
493
+ ```
494
+
495
+ ### Rack Middleware
496
+
497
+ ```ruby
498
+ # config.ru
499
+ require 'anzen'
500
+
501
+ use Anzen::Middleware
502
+
503
+ Anzen.setup(config: {
504
+ enabled_monitors: ['recursion']
505
+ })
506
+ ```
507
+
508
+ ### Standalone Ruby Script
509
+
510
+ ```ruby
511
+ #!/usr/bin/env ruby
512
+ require 'anzen'
513
+
514
+ Anzen.setup(config: {
515
+ enabled_monitors: ['memory'],
516
+ monitors: {
517
+ memory: { limit_mb: 1024 }
518
+ }
519
+ })
520
+
521
+ # Your application code here
522
+ # Anzen automatically checks safety limits
523
+ ```
524
+
525
+ ### Error Handling
526
+
527
+ ```ruby
528
+ begin
529
+ # Risky operation
530
+ process_large_dataset(data)
531
+ rescue Anzen::RecursionLimitExceeded => e
532
+ logger.error("Recursion limit exceeded: #{e.current_depth} > #{e.threshold}")
533
+ # Handle gracefully - retry with smaller chunks
534
+ rescue Anzen::MemoryLimitExceeded => e
535
+ logger.error("Memory limit exceeded: #{e.current_memory_mb}MB > #{e.memory_limit_mb}MB")
536
+ # Clean up resources and exit gracefully
537
+ rescue Anzen::CheckFailedError => e
538
+ logger.error("Monitor check failed: #{e.monitor_name} - #{e.reason}")
539
+ # Infrastructure issue - may need to disable monitor
540
+ end
541
+ ```
542
+
543
+ ### Custom Monitors
544
+
545
+ ```ruby
546
+ class DatabaseConnectionMonitor
547
+ def name; 'database_connections'; end
548
+
549
+ def initialize(config = {})
550
+ @max_connections = config.fetch('max_connections', 100)
551
+ @enabled = false
552
+ @violations = 0
553
+ end
554
+
555
+ def enable; @enabled = true; end
556
+ def disable; @enabled = false; end
557
+ def enabled?; @enabled; end
558
+
559
+ def check!
560
+ return unless enabled?
561
+
562
+ current_connections = ActiveRecord::Base.connection_pool.connections.size
563
+ if current_connections > @max_connections
564
+ raise Anzen::ViolationError.new(
565
+ "Database connections exceeded: #{current_connections} > #{@max_connections}",
566
+ monitor_name: name
567
+ )
568
+ end
569
+ end
570
+
571
+ def status
572
+ {
573
+ status: enabled? ? 'enabled' : 'disabled',
574
+ thresholds: { max_connections: @max_connections },
575
+ violations_detected: @violations
576
+ }
577
+ end
578
+
579
+ def to_cli
580
+ "#{name}: #{enabled? ? 'enabled' : 'disabled'} (max: #{@max_connections})"
581
+ end
582
+ end
583
+
584
+ # Register the custom monitor
585
+ Anzen.register_monitor(DatabaseConnectionMonitor.new(max_connections: 50))
586
+ Anzen.enable('database_connections')
587
+ ```
588
+
589
+ ## Performance Considerations
590
+
591
+ - **Sampling Intervals**: Memory monitor uses sampling to reduce overhead
592
+ - **Selective Enabling**: Only enable monitors you need
593
+ - **Check Frequency**: Call `check!` strategically, not on every operation
594
+ - **Error Handling**: Use rescue blocks to handle violations gracefully
595
+
596
+ ## Thread Safety
597
+
598
+ Anzen is designed to be thread-safe:
599
+ - Monitor state is protected with mutexes
600
+ - Status queries are atomic
601
+ - Configuration is immutable after setup
602
+
603
+ ## Version Compatibility
604
+
605
+ - **Ruby**: 3.0+
606
+ - **Platforms**: Linux, macOS, Windows (with limitations)
607
+ - **Dependencies**: Zero external runtime dependencies</content>
608
+ <parameter name="filePath">/Users/korakot-air/dev/anzen/lib/anzen/README_API.md