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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b0d6abdd8e11593b466a6c75cdb31ae5c7cf9c67a4a03d1f40c77f3b5bda74cd
4
+ data.tar.gz: d710b1070b4f9c4e7889cd7722c32e4fd4ff84a19587979bc27747e57b159e5b
5
+ SHA512:
6
+ metadata.gz: f9b0c437da6c189c1ee234956daa67da7ea14a0940d3a9e6b5abacdfb169016235f868292bd8ead9637350db7e6e01f57aa0e8857f38a4bfc9201d8879a594be
7
+ data.tar.gz: 6f1ad13ac2d366a5a65fff1d69565dbfce647c1c1fe196315659f73f6d0438db9f0cf1d3c6b3b4023c04ea651ed5174020e605fd38887460569fdefb90178b2b
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --require spec_helper
2
+ --format progress
3
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,57 @@
1
+ # RuboCop configuration for Anzen gem
2
+ # Strict mode with selective exceptions for architectural patterns
3
+
4
+ AllCops:
5
+ TargetRubyVersion: 3.0
6
+ NewCops: enable
7
+ SuggestExtensions: false
8
+
9
+ # Disable ClassVars cop: Anzen uses class variables as process-level singleton state
10
+ # This is the appropriate pattern for a module-level safety system that maintains
11
+ # a single registry across the entire process.
12
+ Style/ClassVars:
13
+ Enabled: false
14
+
15
+ # Require frozen string literals
16
+ Style/FrozenStringLiteralComment:
17
+ Enabled: true
18
+
19
+ # Enforce single quotes except where necessary
20
+ Style/StringLiterals:
21
+ Enabled: true
22
+ EnforcedStyle: single_quotes
23
+
24
+ # Enforce double quotes for interpolation
25
+ Style/StringLiteralsInInterpolation:
26
+ Enabled: true
27
+ EnforcedStyle: double_quotes
28
+
29
+ # Require all methods to be documented (public API)
30
+ Style/Documentation:
31
+ Enabled: true
32
+ Exclude:
33
+ - "spec/**/*"
34
+ - "bin/**/*"
35
+
36
+ # Length limits
37
+ Metrics/ClassLength:
38
+ Enabled: true
39
+ Max: 200
40
+
41
+ Metrics/MethodLength:
42
+ Enabled: true
43
+ Max: 30
44
+
45
+ # Layout
46
+ Layout/LineLength:
47
+ Enabled: true
48
+ Max: 120
49
+
50
+ # Naming
51
+ Naming/MethodName:
52
+ Enabled: true
53
+ EnforcedStyle: snake_case
54
+
55
+ # Security
56
+ Security/Eval:
57
+ Enabled: true
data/CHANGELOG.md ADDED
@@ -0,0 +1,51 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Added
11
+
12
+ ### Changed
13
+
14
+ ### Deprecated
15
+
16
+ ### Removed
17
+
18
+ ### Fixed
19
+
20
+ ### Security
21
+
22
+ ## [0.1.0] - 2025-11-17
23
+
24
+ ### Added
25
+ - Initial gem structure and scaffolding
26
+ - Monitor interface and base classes for extensible safety monitoring
27
+ - Recursion detection monitor with call stack depth and pattern-based detection
28
+ - Memory overflow detection monitor with configurable thresholds and sampling
29
+ - Modular registry system for monitor lifecycle management
30
+ - CLI tools (status, config, info, help) for operator monitoring and debugging
31
+ - Configuration management supporting programmatic, environment variable, and file-based setup
32
+ - Comprehensive exception hierarchy with specific violation and infrastructure errors
33
+ - Integration patterns for Rails initializers, Rack middleware, and standalone applications
34
+ - Complete RSpec test suite with 80%+ coverage minimum and integration tests
35
+ - RuboCop linting with strict mode compliance
36
+ - GitHub Actions CI/CD workflows for automated testing and linting
37
+ - Comprehensive YARD documentation for all public APIs
38
+ - Production-ready error handling and graceful degradation patterns
39
+
40
+ ### Changed
41
+
42
+ ### Deprecated
43
+
44
+ ### Removed
45
+
46
+ ### Fixed
47
+
48
+ ### Security
49
+
50
+ [Unreleased]: https://github.com/korakotlee/anzen/compare/v0.1.0...HEAD
51
+ [0.1.0]: https://github.com/korakotlee/anzen/releases/tag/v0.1.0
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ - Using welcoming and inclusive language
18
+ - Being respectful of differing viewpoints and experiences
19
+ - Gracefully accepting constructive criticism
20
+ - Focusing on what is best for the community
21
+ - Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ - The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ - Trolling, insulting/derogatory comments, and personal or political attacks
28
+ - Public or private harassment
29
+ - Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ - Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at <korakot.leemakdej@gmail.com>. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/README.md ADDED
@@ -0,0 +1,321 @@
1
+ # Anzen
2
+
3
+ **Runtime Safety Protection for Ruby Applications**
4
+
5
+ Anzen prevents catastrophic crashes from recursive call stacks and memory overflow conditions. Deploy with confidence knowing your Ruby applications (Rails, microservices, background jobs) are protected from common runtime failures that can bring down production systems.
6
+
7
+ **Key Benefits:**
8
+ - 🚀 **Zero Code Changes**: Drop-in protection with single initialization
9
+ - 🔧 **Enterprise Ready**: Production-tested safety monitoring
10
+ - 📊 **Observable**: CLI tools for status monitoring and debugging
11
+ - 🧩 **Extensible**: Built-in monitors + custom safety checks
12
+ - ⚡ **Low Overhead**: Sampling-based monitoring with minimal performance impact
13
+
14
+ ## Installation
15
+
16
+ Add Anzen to your Gemfile:
17
+
18
+ ```ruby
19
+ gem 'anzen', '~> 0.1.0'
20
+ ```
21
+
22
+ Install the gem:
23
+
24
+ ```bash
25
+ bundle install
26
+ ```
27
+
28
+ ## Quick Start
29
+
30
+ ### Basic Setup (Initializer Pattern)
31
+
32
+ ```ruby
33
+ # config/initializers/anzen.rb (Rails)
34
+ # or lib/anzen.rb (standalone)
35
+
36
+ require 'anzen'
37
+
38
+ Anzen.setup(
39
+ config: {
40
+ enabled_monitors: ['recursion', 'memory'],
41
+ monitors: {
42
+ recursion: { depth_limit: 1000 },
43
+ memory: { limit_mb: 512, sampling_interval_ms: 100 }
44
+ }
45
+ }
46
+ )
47
+
48
+ # Your application is now protected!
49
+ ```
50
+
51
+ ### Protection in Action
52
+
53
+ ```ruby
54
+ def risky_algorithm(n)
55
+ return n if n <= 1
56
+ # Anzen automatically checks safety limits
57
+ risky_algorithm(n - 1) + risky_algorithm(n - 2)
58
+ end
59
+
60
+ begin
61
+ result = risky_algorithm(50) # Safe with Anzen
62
+ rescue Anzen::RecursionLimitExceeded => e
63
+ puts "Recursion limit exceeded: #{e.current_depth} > #{e.threshold}"
64
+ # Handle gracefully instead of crashing
65
+ rescue Anzen::MemoryLimitExceeded => e
66
+ puts "Memory limit exceeded: #{e.current_memory_mb}MB > #{e.memory_limit_mb}MB"
67
+ # Clean up and retry with smaller dataset
68
+ end
69
+ ```
70
+
71
+ ## Configuration
72
+
73
+ Anzen supports multiple configuration sources:
74
+
75
+ ### Environment Variables
76
+
77
+ ```bash
78
+ export ANZEN_CONFIG='{
79
+ "enabled_monitors": ["recursion", "memory"],
80
+ "monitors": {
81
+ "recursion": {"depth_limit": 500},
82
+ "memory": {"limit_mb": 1024}
83
+ }
84
+ }'
85
+ ```
86
+
87
+ ### Configuration File
88
+
89
+ ```yaml
90
+ # config/anzen.yml
91
+ anzen:
92
+ enabled_monitors:
93
+ - recursion
94
+ - memory
95
+ monitors:
96
+ recursion:
97
+ depth_limit: 1000
98
+ memory:
99
+ limit_mb: 512
100
+ sampling_interval_ms: 100
101
+ ```
102
+
103
+ ### Programmatic Setup
104
+
105
+ ```ruby
106
+ Anzen.setup(config: {
107
+ enabled_monitors: ['recursion'],
108
+ monitors: {
109
+ recursion: { depth_limit: 500 }
110
+ }
111
+ })
112
+ ```
113
+
114
+ ## CLI Commands
115
+
116
+ Anzen provides command-line tools for monitoring and debugging:
117
+
118
+ ```bash
119
+ # Show protection status
120
+ anzen status
121
+
122
+ # View configuration
123
+ anzen config
124
+ anzen config memory --format json
125
+
126
+ # System information
127
+ anzen info
128
+
129
+ # Help and version
130
+ anzen help
131
+ anzen --version
132
+ ```
133
+
134
+ ### Example CLI Output
135
+
136
+ ```bash
137
+ $ anzen status
138
+ Anzen Safety Protection Status
139
+ ========================================
140
+
141
+ Enabled Monitors: recursion, memory
142
+
143
+ Monitor: recursion
144
+ Status: enabled
145
+ Thresholds:
146
+ depth_limit: 1000
147
+ Last Check: never
148
+ Violations Detected: 0
149
+
150
+ Monitor: memory
151
+ Status: enabled
152
+ Thresholds:
153
+ limit_mb: 512
154
+ sampling_interval_ms: 100
155
+ Last Check: never
156
+ Violations Detected: 0
157
+
158
+ Total Violations: 0
159
+ Setup Time: 2025-11-17 17:05:02 EST
160
+ ```
161
+
162
+ ## Integration Patterns
163
+
164
+ Anzen integrates cleanly with any Ruby application:
165
+
166
+ ### Rails Applications
167
+ - **Initializer**: `config/initializers/anzen.rb`
168
+ - **Middleware**: Automatic request-level protection
169
+ - **Background Jobs**: Sidekiq/Resque job protection
170
+
171
+ ### Rack Applications
172
+ - **Middleware**: `use Anzen::Middleware`
173
+ - **Config.ru**: Centralized setup
174
+
175
+ ### Standalone Scripts
176
+ - **Direct Setup**: `Anzen.setup()` at script start
177
+ - **Error Handling**: Rescue `Anzen::ViolationError`
178
+
179
+ ## API Reference
180
+
181
+ ### Core Methods
182
+
183
+ ```ruby
184
+ # Initialize protection
185
+ Anzen.setup(config: {...})
186
+
187
+ # Runtime control
188
+ Anzen.enable('recursion')
189
+ Anzen.disable('memory')
190
+
191
+ # Status and monitoring
192
+ status = Anzen.status
193
+ Anzen.check! # Manual safety check
194
+
195
+ # Custom monitors
196
+ Anzen.register_monitor(my_monitor)
197
+ ```
198
+
199
+ ### Exception Types
200
+
201
+ ```ruby
202
+ begin
203
+ Anzen.check!
204
+ rescue Anzen::RecursionLimitExceeded => e
205
+ # Recursion violation
206
+ rescue Anzen::MemoryLimitExceeded => e
207
+ # Memory violation
208
+ rescue Anzen::CheckFailedError => e
209
+ # Infrastructure error
210
+ end
211
+ ```
212
+
213
+ ## Troubleshooting
214
+
215
+ ### Common Issues
216
+
217
+ **"Anzen not initialized"**
218
+ - Ensure `Anzen.setup()` is called before using CLI or API
219
+ - Check that the gem is properly required
220
+
221
+ **High Memory Usage**
222
+ - Adjust `sampling_interval_ms` to reduce monitoring frequency
223
+ - Memory monitor only samples, doesn't cause overhead
224
+
225
+ **Recursion Detection Too Sensitive**
226
+ - Increase `depth_limit` for applications with deep call stacks
227
+ - Recursion monitor tracks all method calls including framework code
228
+
229
+ **CLI Commands Not Found**
230
+ - Ensure `bin/anzen` is in PATH or use `bundle exec anzen`
231
+ - Check that the gem is installed: `gem list anzen`
232
+
233
+ ### Debug Mode
234
+
235
+ Enable verbose logging:
236
+
237
+ ```ruby
238
+ Anzen.setup(config: {
239
+ # ... normal config ...
240
+ debug: true # Future enhancement
241
+ })
242
+ ```
243
+
244
+ ### Performance Tuning
245
+
246
+ ```ruby
247
+ # Reduce monitoring overhead
248
+ Anzen.setup(config: {
249
+ enabled_monitors: ['recursion'], # Only enable needed monitors
250
+ monitors: {
251
+ memory: {
252
+ sampling_interval_ms: 500 # Check less frequently
253
+ }
254
+ }
255
+ })
256
+ ```
257
+
258
+ ## Development
259
+
260
+ ### Prerequisites
261
+
262
+ - Ruby 3.0+
263
+ - Bundler
264
+
265
+ ### Setup
266
+
267
+ ```bash
268
+ git clone https://github.com/korakotlee/anzen
269
+ cd anzen
270
+ bin/setup
271
+ ```
272
+
273
+ ### Testing
274
+
275
+ ```bash
276
+ # Run all tests
277
+ bundle exec rspec
278
+
279
+ # Run with coverage
280
+ bundle exec rspec --coverage
281
+
282
+ # Run specific test
283
+ bundle exec rspec spec/unit/cli_spec.rb
284
+ ```
285
+
286
+ ### Code Quality
287
+
288
+ ```bash
289
+ # Lint code
290
+ bundle exec rubocop
291
+
292
+ # Auto-fix issues
293
+ bundle exec rubocop -a
294
+
295
+ # Run all checks
296
+ bundle exec rake
297
+ ```
298
+
299
+ ## Contributing
300
+
301
+ 1. Fork the repository
302
+ 2. Create a feature branch: `git checkout -b feature/my-feature`
303
+ 3. Write tests for your changes
304
+ 4. Ensure all tests pass: `bundle exec rspec`
305
+ 5. Check code quality: `bundle exec rubocop`
306
+ 6. Submit a pull request
307
+
308
+ ### Development Guidelines
309
+
310
+ - **Test-First**: Write specs before implementation
311
+ - **Code Quality**: RuboCop strict compliance required
312
+ - **Documentation**: Update docs for public API changes
313
+ - **Backwards Compatibility**: Maintain API stability
314
+
315
+ ## License
316
+
317
+ Copyright (c) 2025 Korakot Lee. Released under the MIT License. See [LICENSE](./LICENSE) for details.
318
+
319
+ ## Code of Conduct
320
+
321
+ This project follows the [Contributor Covenant](./CODE_OF_CONDUCT.md). We are committed to providing a welcoming and inclusive environment for all contributors.
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+ require "rubocop/rake_task"
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+ RuboCop::RakeTask.new(:rubocop)
9
+
10
+ task default: %i[spec rubocop]
11
+
12
+ namespace :ci do
13
+ desc "Run all CI checks (tests + lint)"
14
+ task check: %i[spec rubocop]
15
+ end
16
+
17
+ namespace :coverage do
18
+ desc "Show test coverage report"
19
+ task report: :spec do
20
+ require "simplecov"
21
+ puts "\nCoverage report available in coverage/index.html"
22
+ end
23
+ end
data/bin/anzen ADDED
@@ -0,0 +1,168 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Anzen CLI executable
5
+ # Provides command-line interface for Anzen safety monitoring
6
+
7
+ # Add lib directory to load path when running from source
8
+ $LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
9
+
10
+ require 'optparse'
11
+ require 'anzen'
12
+ require 'anzen/cli'
13
+
14
+ # Exit codes
15
+ EXIT_SUCCESS = 0
16
+ EXIT_ANZEN_NOT_INITIALIZED = 1
17
+ EXIT_INVALID_ARGUMENTS = 2
18
+ EXIT_MONITOR_NOT_FOUND = 3
19
+ EXIT_CONFIGURATION_ERROR = 4
20
+ EXIT_COMMAND_NOT_FOUND = 127
21
+
22
+ def main
23
+ # Check for test initialization flag
24
+ if ARGV.include?('--test-init')
25
+ ARGV.delete('--test-init')
26
+ # Initialize Anzen with test configuration for integration testing
27
+ begin
28
+ Anzen.setup(
29
+ config: {
30
+ enabled_monitors: %w[recursion memory],
31
+ monitors: {
32
+ recursion: { depth_limit: 1000 },
33
+ memory: { limit_mb: 512, sampling_interval_ms: 100 }
34
+ }
35
+ }
36
+ )
37
+ rescue Anzen::InitializationError
38
+ # Already initialized, continue
39
+ end
40
+ end
41
+
42
+ # Parse command line arguments first
43
+ options = parse_options
44
+
45
+ # Handle commands that don't require initialization
46
+ case options[:command]
47
+ when 'help'
48
+ cli = Anzen::CLI.new
49
+ output = execute_command(cli, options)
50
+ puts output
51
+ exit EXIT_SUCCESS
52
+ when 'version'
53
+ puts "anzen #{Anzen::VERSION}"
54
+ exit EXIT_SUCCESS
55
+ end
56
+
57
+ # Check if Anzen is initialized for other commands
58
+ unless anzen_initialized?
59
+ warn 'Error: Anzen not initialized'
60
+ warn 'Application must call Anzen.setup() before CLI can be used'
61
+ exit EXIT_ANZEN_NOT_INITIALIZED
62
+ end
63
+
64
+ # Execute command
65
+ begin
66
+ cli = Anzen::CLI.new
67
+ output = execute_command(cli, options)
68
+ puts output
69
+ exit EXIT_SUCCESS
70
+ rescue ArgumentError => e
71
+ warn "Error: #{e.message}"
72
+ exit EXIT_INVALID_ARGUMENTS
73
+ rescue Anzen::MonitorNotFoundError => e
74
+ warn "Error: #{e.message}"
75
+ exit EXIT_MONITOR_NOT_FOUND
76
+ rescue Anzen::ConfigurationError => e
77
+ warn "Error: #{e.message}"
78
+ exit EXIT_CONFIGURATION_ERROR
79
+ rescue StandardError => e
80
+ warn "Unexpected error: #{e.message}"
81
+ exit EXIT_COMMAND_NOT_FOUND
82
+ end
83
+ end
84
+
85
+ def anzen_initialized?
86
+ # Check if Anzen has been set up by looking for registry
87
+
88
+ Anzen.status
89
+ true
90
+ rescue StandardError
91
+ false
92
+ end
93
+
94
+ def parse_options
95
+ options = {
96
+ command: nil,
97
+ monitor_name: nil,
98
+ format: :text
99
+ }
100
+
101
+ parser = OptionParser.new do |opts|
102
+ opts.banner = 'Usage: anzen [command] [options]'
103
+
104
+ opts.on('-v', '--version', 'Show gem version') do
105
+ options[:command] = 'version'
106
+ end
107
+
108
+ opts.on('--format FORMAT', 'Output format: json, text (default: text)') do |format|
109
+ options[:format] = format.to_sym
110
+ end
111
+
112
+ opts.on('-h', '--help', 'Show help') do
113
+ options[:command] = 'help'
114
+ end
115
+ end
116
+
117
+ # Parse all options first
118
+ parser.parse!
119
+
120
+ # If no command was set by options, check positional arguments
121
+ unless options[:command]
122
+ if ARGV.empty?
123
+ options[:command] = 'help'
124
+ else
125
+ command = ARGV.shift
126
+ options[:command] = command
127
+
128
+ # For config command, next argument might be monitor name
129
+ options[:monitor_name] = ARGV.shift if command == 'config' && !ARGV.empty? && !ARGV.first.start_with?('-')
130
+
131
+ # For help command, next argument might be specific command
132
+ options[:help_command] = ARGV.shift if command == 'help' && !ARGV.empty? && !ARGV.first.start_with?('-')
133
+ end
134
+ end
135
+
136
+ options
137
+ end
138
+
139
+ def execute_command(cli, options)
140
+ command = options[:command]
141
+ format = options[:format]
142
+
143
+ case command
144
+ when 'status'
145
+ cli.status(format: format)
146
+ when 'config'
147
+ if options[:monitor_name]
148
+ cli.config(monitor_name: options[:monitor_name], format: format)
149
+ else
150
+ cli.config(format: format)
151
+ end
152
+ when 'info'
153
+ cli.info(format: format)
154
+ when 'help'
155
+ if options[:help_command]
156
+ cli.help(command: options[:help_command])
157
+ else
158
+ cli.help
159
+ end
160
+ when 'version'
161
+ "anzen #{Anzen::VERSION}"
162
+ else
163
+ raise ArgumentError, "Unknown command '#{command}'. Use 'anzen help' for available commands."
164
+ end
165
+ end
166
+
167
+ # Run the CLI
168
+ main