coverband 6.1.6 → 6.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.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +4 -4
- data/README.md +123 -0
- data/agents.md +217 -0
- data/bin/coverband-mcp +42 -0
- data/changes.md +18 -0
- data/coverband/log.272267 +1 -0
- data/coverband.gemspec +3 -1
- data/lib/coverband/collectors/route_tracker.rb +1 -1
- data/lib/coverband/collectors/view_tracker.rb +21 -13
- data/lib/coverband/configuration.rb +57 -18
- data/lib/coverband/integrations/resque.rb +2 -2
- data/lib/coverband/mcp/http_handler.rb +118 -0
- data/lib/coverband/mcp/server.rb +116 -0
- data/lib/coverband/mcp/tools/get_coverage_summary.rb +41 -0
- data/lib/coverband/mcp/tools/get_dead_methods.rb +69 -0
- data/lib/coverband/mcp/tools/get_file_coverage.rb +72 -0
- data/lib/coverband/mcp/tools/get_route_tracker_data.rb +60 -0
- data/lib/coverband/mcp/tools/get_translation_tracker_data.rb +60 -0
- data/lib/coverband/mcp/tools/get_uncovered_files.rb +73 -0
- data/lib/coverband/mcp/tools/get_view_tracker_data.rb +60 -0
- data/lib/coverband/mcp.rb +27 -0
- data/lib/coverband/reporters/base.rb +2 -4
- data/lib/coverband/reporters/web.rb +17 -14
- data/lib/coverband/utils/lines_classifier.rb +1 -1
- data/lib/coverband/utils/result.rb +2 -1
- data/lib/coverband/utils/source_file.rb +5 -5
- data/lib/coverband/utils/tasks.rb +31 -0
- data/lib/coverband/version.rb +1 -1
- data/lib/coverband.rb +2 -2
- data/test/coverband/file_store_integration_test.rb +72 -0
- data/test/coverband/file_store_redis_error_test.rb +56 -0
- data/test/coverband/github_issue_586_test.rb +46 -0
- data/test/coverband/initialization_timing_test.rb +71 -0
- data/test/coverband/mcp/http_handler_test.rb +159 -0
- data/test/coverband/mcp/security_test.rb +145 -0
- data/test/coverband/mcp/server_test.rb +125 -0
- data/test/coverband/mcp/tools/get_coverage_summary_test.rb +75 -0
- data/test/coverband/mcp/tools/get_dead_methods_test.rb +162 -0
- data/test/coverband/mcp/tools/get_file_coverage_test.rb +159 -0
- data/test/coverband/mcp/tools/get_route_tracker_data_test.rb +122 -0
- data/test/coverband/mcp/tools/get_translation_tracker_data_test.rb +122 -0
- data/test/coverband/mcp/tools/get_uncovered_files_test.rb +177 -0
- data/test/coverband/mcp/tools/get_view_tracker_data_test.rb +122 -0
- data/test/coverband/reporters/web_test.rb +5 -0
- data/test/coverband/tracker_initialization_test.rb +75 -0
- data/test/coverband/user_environment_simulation_test.rb +75 -0
- data/test/coverband/utils/lines_classifier_test.rb +1 -1
- data/test/integration/mcp_integration_test.rb +175 -0
- data/test/test_helper.rb +4 -5
- metadata +65 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e3ae4783bfea151c9e3b5d58e397467085206359b6c3446df24ad136fc067ca3
|
|
4
|
+
data.tar.gz: c7491d46394412b813447b80e21ca29e1cfe62060b54a28a14a6145a8ec5eb84
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2cbd8715bf8a5ea95e5705038acec36bd8549fb9ca01b99c4266919904122fb9fd81cbc3e1488d6eaa0c0bb955875c429751523843449abc0c5d01107d620085
|
|
7
|
+
data.tar.gz: f4ac2904d9cde83162aa3f1d350aeb25e337f8c86178b79668170ae00ef64df9d564e15cdd94597cb1ea6652daa244b8454cdc8c3401e14b74662527ff7ea34e
|
data/.github/workflows/main.yml
CHANGED
|
@@ -21,7 +21,7 @@ jobs:
|
|
|
21
21
|
# removing jruby again to flaky
|
|
22
22
|
gemfile: [ Gemfile.rails7.0, Gemfile.rails7.1, Gemfile.rails7.2, Gemfile.rails8.0 ]
|
|
23
23
|
# need to add support for multiple gemfiles
|
|
24
|
-
ruby: ["3.1", "3.2", "3.3", "3.4", "ruby-head"]
|
|
24
|
+
ruby: ["3.1", "3.2", "3.3", "3.4", "4.0", "ruby-head"]
|
|
25
25
|
redis-version: [4, 5, 6, 7]
|
|
26
26
|
exclude:
|
|
27
27
|
# Rails 8 requires ruby 3.2+.
|
|
@@ -29,8 +29,8 @@ jobs:
|
|
|
29
29
|
ruby: '3.1'
|
|
30
30
|
runs-on: ${{ matrix.os }}-latest
|
|
31
31
|
steps:
|
|
32
|
-
- uses: actions/checkout@
|
|
33
|
-
- uses: supercharge/redis-github-action@
|
|
32
|
+
- uses: actions/checkout@v6
|
|
33
|
+
- uses: supercharge/redis-github-action@v2
|
|
34
34
|
with:
|
|
35
35
|
redis-version: ${{ matrix.redis-version }}
|
|
36
36
|
- uses: ruby/setup-ruby@v1
|
|
@@ -42,7 +42,7 @@ jobs:
|
|
|
42
42
|
starndardrb:
|
|
43
43
|
runs-on: ubuntu-latest
|
|
44
44
|
steps:
|
|
45
|
-
- uses: actions/checkout@
|
|
45
|
+
- uses: actions/checkout@v6
|
|
46
46
|
- uses: ruby/setup-ruby@v1
|
|
47
47
|
with:
|
|
48
48
|
ruby-version: 3.1
|
data/README.md
CHANGED
|
@@ -406,6 +406,129 @@ A few folks have asked about what size of Redis is needed to run Coverband. I ha
|
|
|
406
406
|
|
|
407
407
|
# Newer Features
|
|
408
408
|
|
|
409
|
+
### MCP Server for AI Assistants
|
|
410
|
+
|
|
411
|
+
Coverband includes an optional MCP (Model Context Protocol) server that allows AI assistants like Claude to query your production coverage data directly. This enables AI-powered code analysis, dead code detection, and coverage insights.
|
|
412
|
+
|
|
413
|
+
#### Installation
|
|
414
|
+
|
|
415
|
+
Add the MCP gem to your Gemfile:
|
|
416
|
+
|
|
417
|
+
```ruby
|
|
418
|
+
gem 'mcp'
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
#### Available Tools
|
|
422
|
+
|
|
423
|
+
The MCP server provides the following tools:
|
|
424
|
+
|
|
425
|
+
| Tool | Description |
|
|
426
|
+
|------|-------------|
|
|
427
|
+
| `get_coverage_summary` | Get overall coverage statistics |
|
|
428
|
+
| `get_file_coverage` | Get detailed coverage for a specific file |
|
|
429
|
+
| `get_uncovered_files` | List files with no coverage data |
|
|
430
|
+
| `get_dead_methods` | Find methods that are never called |
|
|
431
|
+
| `get_view_tracker_data` | Get view/template usage data |
|
|
432
|
+
| `get_route_tracker_data` | Get route usage statistics |
|
|
433
|
+
| `get_translation_tracker_data` | Get translation key usage data |
|
|
434
|
+
|
|
435
|
+
#### Running the MCP Server
|
|
436
|
+
|
|
437
|
+
**Standalone (stdio transport):**
|
|
438
|
+
|
|
439
|
+
```bash
|
|
440
|
+
bundle exec coverband-mcp
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
**With a rake task:**
|
|
444
|
+
|
|
445
|
+
```bash
|
|
446
|
+
bundle exec rake coverband:mcp
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
**HTTP mode (for remote access):**
|
|
450
|
+
|
|
451
|
+
```bash
|
|
452
|
+
COVERBAND_MCP_HTTP=true COVERBAND_MCP_PORT=9023 bundle exec rake coverband:mcp
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
#### Configuring Claude Desktop
|
|
456
|
+
|
|
457
|
+
Add to your Claude Desktop configuration (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
|
|
458
|
+
|
|
459
|
+
**Option 1: Stdio transport (recommended for local development)**
|
|
460
|
+
|
|
461
|
+
```json
|
|
462
|
+
{
|
|
463
|
+
"mcpServers": {
|
|
464
|
+
"coverband": {
|
|
465
|
+
"command": "bundle",
|
|
466
|
+
"args": ["exec", "coverband-mcp"],
|
|
467
|
+
"cwd": "/path/to/your/rails/app"
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
**Option 2: HTTP transport (for remote access or shared servers)**
|
|
474
|
+
|
|
475
|
+
First, start the MCP server in HTTP mode:
|
|
476
|
+
|
|
477
|
+
```bash
|
|
478
|
+
COVERBAND_MCP_HTTP=true bundle exec rake coverband:mcp
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
Then configure Claude Desktop to connect via `mcp-remote`:
|
|
482
|
+
|
|
483
|
+
```json
|
|
484
|
+
{
|
|
485
|
+
"mcpServers": {
|
|
486
|
+
"coverband": {
|
|
487
|
+
"command": "npx",
|
|
488
|
+
"args": ["mcp-remote", "http://localhost:9023"]
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
#### Configuring Claude Code
|
|
495
|
+
|
|
496
|
+
Add a `.mcp.json` file to your project root:
|
|
497
|
+
|
|
498
|
+
**Option 1: Stdio transport (recommended)**
|
|
499
|
+
|
|
500
|
+
```json
|
|
501
|
+
{
|
|
502
|
+
"mcpServers": {
|
|
503
|
+
"coverband": {
|
|
504
|
+
"command": "bundle",
|
|
505
|
+
"args": ["exec", "coverband-mcp"]
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
**Option 2: HTTP transport**
|
|
512
|
+
|
|
513
|
+
```json
|
|
514
|
+
{
|
|
515
|
+
"mcpServers": {
|
|
516
|
+
"coverband": {
|
|
517
|
+
"command": "npx",
|
|
518
|
+
"args": ["mcp-remote", "http://localhost:9023"]
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
#### Environment Variables
|
|
525
|
+
|
|
526
|
+
| Variable | Description | Default |
|
|
527
|
+
|----------|-------------|---------|
|
|
528
|
+
| `COVERBAND_MCP_HTTP` | Enable HTTP transport instead of stdio | `false` |
|
|
529
|
+
| `COVERBAND_MCP_PORT` | Port for HTTP server | `9023` |
|
|
530
|
+
| `COVERBAND_REDIS_URL` | Redis URL for coverage data | `localhost:6379` |
|
|
531
|
+
|
|
409
532
|
### Dead Method Scanning (ruby 2.6+)
|
|
410
533
|
|
|
411
534
|
Rake task that outputs dead methods based on current coverage data:
|
data/agents.md
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# AI Agent Guidelines for Coverband Development
|
|
2
|
+
|
|
3
|
+
This document provides guidance for AI coding agents working on the Coverband project. Following these guidelines ensures code quality and consistency.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
Coverband is a Ruby gem that provides rack middleware to measure production code usage (LOC runtime usage). The project uses:
|
|
8
|
+
- **Ruby**: >= 3.1
|
|
9
|
+
- **Test Framework**: Minitest (version ~> 5.0)
|
|
10
|
+
- **Code Style**: StandardRB
|
|
11
|
+
- **CI/CD**: GitHub Actions
|
|
12
|
+
|
|
13
|
+
## Testing Requirements
|
|
14
|
+
|
|
15
|
+
### Running Tests
|
|
16
|
+
|
|
17
|
+
All code changes MUST pass the test suite before considering work complete. The project has multiple test targets:
|
|
18
|
+
|
|
19
|
+
#### Standard Test Suite
|
|
20
|
+
```bash
|
|
21
|
+
bundle exec rake test
|
|
22
|
+
```
|
|
23
|
+
This runs the main integration and unit tests located in:
|
|
24
|
+
- `test/integration/**/*_test.rb`
|
|
25
|
+
- `test/coverband/**/*_test.rb`
|
|
26
|
+
|
|
27
|
+
#### Forked Tests
|
|
28
|
+
```bash
|
|
29
|
+
bundle exec rake forked_tests
|
|
30
|
+
```
|
|
31
|
+
Runs tests that require forked processes (Rails integration tests):
|
|
32
|
+
- `test/forked/**/*_test.rb`
|
|
33
|
+
|
|
34
|
+
Note: Forked tests are not supported on JRuby.
|
|
35
|
+
|
|
36
|
+
#### Full Test Suite
|
|
37
|
+
```bash
|
|
38
|
+
bundle exec rake test:all
|
|
39
|
+
```
|
|
40
|
+
Runs all tests including benchmarks and memory tests.
|
|
41
|
+
|
|
42
|
+
#### Default Task
|
|
43
|
+
```bash
|
|
44
|
+
bundle exec rake
|
|
45
|
+
```
|
|
46
|
+
Equivalent to `bundle exec rake test`
|
|
47
|
+
|
|
48
|
+
### Test Framework Details
|
|
49
|
+
|
|
50
|
+
- Uses **Minitest** with **Mocha** for mocking
|
|
51
|
+
- Test files follow the pattern `*_test.rb`
|
|
52
|
+
- Rails integration tests use **Capybara** for browser testing
|
|
53
|
+
- Forked tests use `minitest-fork_executor` for parallel execution
|
|
54
|
+
|
|
55
|
+
### Test Configuration
|
|
56
|
+
|
|
57
|
+
Key test dependencies:
|
|
58
|
+
- `minitest ~> 5.0` (pinned for compatibility with minitest-fork_executor)
|
|
59
|
+
- `mocha` for mocking/stubbing
|
|
60
|
+
- `minitest-stub-const` for constant stubbing
|
|
61
|
+
- `capybara` for integration testing
|
|
62
|
+
- `rack-test` for Rack testing
|
|
63
|
+
|
|
64
|
+
## Code Style Requirements
|
|
65
|
+
|
|
66
|
+
### StandardRB
|
|
67
|
+
|
|
68
|
+
All code MUST pass StandardRB linting before considering work complete.
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
bundle exec standardrb --format github
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
#### Auto-fix Style Issues
|
|
75
|
+
```bash
|
|
76
|
+
bundle exec standardrb --fix
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Configuration
|
|
80
|
+
|
|
81
|
+
StandardRB configuration is in `.standard.yml`:
|
|
82
|
+
- Ruby version: 3.1
|
|
83
|
+
- Parallel execution enabled
|
|
84
|
+
- Some rules are disabled for compatibility with older Ruby versions
|
|
85
|
+
- Test files have relaxed rules (see `.standard.yml` for specifics)
|
|
86
|
+
|
|
87
|
+
### Common Style Requirements
|
|
88
|
+
|
|
89
|
+
1. **Module Inclusions**: Add an empty line after `extend` or `include` statements
|
|
90
|
+
2. **Frozen String Literals**: All Ruby files should start with `# frozen_string_literal: true`
|
|
91
|
+
3. **Line Length**: Follow StandardRB defaults (no manual line length configuration needed)
|
|
92
|
+
|
|
93
|
+
## AI Agent Workflow
|
|
94
|
+
|
|
95
|
+
When making code changes, follow this workflow:
|
|
96
|
+
|
|
97
|
+
### 1. Make Code Changes
|
|
98
|
+
Implement the requested feature or bug fix.
|
|
99
|
+
|
|
100
|
+
### 2. Run Tests
|
|
101
|
+
```bash
|
|
102
|
+
bundle exec rake test
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
If working on Rails integration or forked features:
|
|
106
|
+
```bash
|
|
107
|
+
bundle exec rake test:all
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 3. Fix Any Test Failures
|
|
111
|
+
- Read test output carefully
|
|
112
|
+
- Fix issues in the code
|
|
113
|
+
- Re-run tests until all pass
|
|
114
|
+
|
|
115
|
+
### 4. Check Code Style
|
|
116
|
+
```bash
|
|
117
|
+
bundle exec standardrb --format github
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 5. Auto-fix Style Issues (if any)
|
|
121
|
+
```bash
|
|
122
|
+
bundle exec standardrb --fix
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 6. Verify Everything Passes
|
|
126
|
+
```bash
|
|
127
|
+
bundle exec rake test
|
|
128
|
+
bundle exec standardrb --format github
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### 7. Only Then Consider Work Complete
|
|
132
|
+
Do NOT mark work as complete or hand back to the user until:
|
|
133
|
+
- ✅ All tests pass
|
|
134
|
+
- ✅ StandardRB reports no violations
|
|
135
|
+
|
|
136
|
+
## Common Issues and Solutions
|
|
137
|
+
|
|
138
|
+
### Mocha Configuration
|
|
139
|
+
- Use only Mocha 3.x compatible configuration options
|
|
140
|
+
- Valid options: `stubbing_method_unnecessarily`, `stubbing_non_public_method`
|
|
141
|
+
- Invalid options (removed): `stubbing_method_on_nil`, `stubbing_method_on_non_mock_object`, `stubbing_non_existent_method`
|
|
142
|
+
|
|
143
|
+
### Rails Constant Checks
|
|
144
|
+
When checking if Rails is defined:
|
|
145
|
+
```ruby
|
|
146
|
+
# ✅ Correct
|
|
147
|
+
if defined?(Rails) && Rails.respond_to?(:version)
|
|
148
|
+
# ...
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# ❌ Wrong (doesn't protect against undefined constant)
|
|
152
|
+
if Rails&.respond_to?(:version)
|
|
153
|
+
# ...
|
|
154
|
+
end
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Minitest Version
|
|
158
|
+
- Must use Minitest ~> 5.0 for compatibility with `minitest-fork_executor`
|
|
159
|
+
- Minitest 6.0+ is not compatible with the fork executor
|
|
160
|
+
|
|
161
|
+
## CI/CD
|
|
162
|
+
|
|
163
|
+
The project uses GitHub Actions for CI. On every push/PR:
|
|
164
|
+
1. Tests run against multiple Ruby versions (3.1, 3.2, 3.3, 3.4, ruby-head)
|
|
165
|
+
2. Tests run against multiple Rails versions (7.0, 7.1, 7.2, 8.0)
|
|
166
|
+
3. Tests run against multiple Redis versions (4, 5, 6, 7)
|
|
167
|
+
4. StandardRB runs separately to check code style
|
|
168
|
+
|
|
169
|
+
Your local testing should match CI requirements:
|
|
170
|
+
- All tests must pass
|
|
171
|
+
- StandardRB must report no violations
|
|
172
|
+
|
|
173
|
+
## Additional Notes
|
|
174
|
+
|
|
175
|
+
- The project uses Redis as the default storage backend
|
|
176
|
+
- Rails 8.0 requires Ruby 3.2+
|
|
177
|
+
- Test coverage data is stored in `/tmp` during tests
|
|
178
|
+
- Use `test_helper.rb` for common test setup
|
|
179
|
+
- Use `rails_test_helper.rb` for Rails-specific test setup
|
|
180
|
+
|
|
181
|
+
## Example Complete Workflow
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# 1. Make changes to code
|
|
185
|
+
vim lib/coverband/some_file.rb
|
|
186
|
+
|
|
187
|
+
# 2. Run tests
|
|
188
|
+
bundle exec rake test
|
|
189
|
+
|
|
190
|
+
# 3. Fix any failures, re-run until passing
|
|
191
|
+
bundle exec rake test
|
|
192
|
+
|
|
193
|
+
# 4. Check style
|
|
194
|
+
bundle exec standardrb --format github
|
|
195
|
+
|
|
196
|
+
# 5. Auto-fix any style issues
|
|
197
|
+
bundle exec standardrb --fix
|
|
198
|
+
|
|
199
|
+
# 6. Final verification
|
|
200
|
+
bundle exec rake test
|
|
201
|
+
bundle exec standardrb --format github
|
|
202
|
+
|
|
203
|
+
# 7. All green? Work is complete! ✅
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Quick Reference
|
|
207
|
+
|
|
208
|
+
| Command | Purpose |
|
|
209
|
+
|---------|---------|
|
|
210
|
+
| `bundle exec rake` | Run main test suite (default) |
|
|
211
|
+
| `bundle exec rake test` | Run main test suite |
|
|
212
|
+
| `bundle exec rake forked_tests` | Run forked/Rails integration tests |
|
|
213
|
+
| `bundle exec rake test:all` | Run all tests including benchmarks |
|
|
214
|
+
| `bundle exec standardrb --format github` | Check code style |
|
|
215
|
+
| `bundle exec standardrb --fix` | Auto-fix style issues |
|
|
216
|
+
|
|
217
|
+
Remember: **Tests and style checks must pass before work is considered complete!**
|
data/bin/coverband-mcp
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "bundler/setup"
|
|
5
|
+
require "coverband/mcp"
|
|
6
|
+
|
|
7
|
+
# Ensure Coverband is configured
|
|
8
|
+
Coverband.configure unless Coverband.configured?
|
|
9
|
+
|
|
10
|
+
# Security check and warning
|
|
11
|
+
unless Coverband.configuration.mcp_enabled?
|
|
12
|
+
puts "❌ ERROR: MCP is not enabled for security reasons."
|
|
13
|
+
puts "To enable MCP access, configure Coverband with:"
|
|
14
|
+
puts
|
|
15
|
+
puts "Coverband.configure do |config|"
|
|
16
|
+
puts " config.mcp_enabled = true"
|
|
17
|
+
puts " config.mcp_password = 'your-secure-password' # Recommended"
|
|
18
|
+
puts " config.mcp_allowed_environments = %w[development staging production] # As needed"
|
|
19
|
+
puts "end"
|
|
20
|
+
puts
|
|
21
|
+
puts "Or set environment variables:"
|
|
22
|
+
puts " COVERBAND_MCP_PASSWORD=your-secure-password"
|
|
23
|
+
puts
|
|
24
|
+
puts "Current environment: #{(defined?(Rails) && Rails.respond_to?(:env) && Rails.env) || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"}"
|
|
25
|
+
exit 1
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Display security status
|
|
29
|
+
puts "🔐 SECURITY STATUS:"
|
|
30
|
+
if Coverband.configuration.mcp_password
|
|
31
|
+
puts " ✅ Authentication: Enabled (password protected)"
|
|
32
|
+
else
|
|
33
|
+
puts " ⚠️ Authentication: DISABLED - Consider setting mcp_password for production use"
|
|
34
|
+
end
|
|
35
|
+
env = (defined?(Rails) && Rails.respond_to?(:env) && Rails.env) || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
|
36
|
+
puts " 📍 Environment: #{env}"
|
|
37
|
+
puts " 🌍 Allowed environments: #{Coverband.configuration.mcp_allowed_environments.join(", ")}"
|
|
38
|
+
puts
|
|
39
|
+
|
|
40
|
+
# Start the MCP server with stdio transport
|
|
41
|
+
server = Coverband::MCP::Server.new
|
|
42
|
+
server.run_stdio
|
data/changes.md
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
### Coverband 6.1.7
|
|
2
|
+
|
|
3
|
+
* add back a running demo site
|
|
4
|
+
* source: https://github.com/danmayer/coverband_rails_example
|
|
5
|
+
* demo site: https://coverband-rails-example.onrender.com/demo
|
|
6
|
+
* Feature: Added MCP (Model Context Protocol) server support for AI assistants
|
|
7
|
+
* Allows AI agents (like Claude) to securely query coverage data, find dead code, and analyze usage
|
|
8
|
+
* Includes HTTP and Stdio transports
|
|
9
|
+
* See `docs/mcp_security.md` and README for setup instructions
|
|
10
|
+
* Feature: Added `Coverband::MCP::HttpHandler` for mounting MCP server in Rack apps
|
|
11
|
+
* Improvement: Added `routes_tracker` alias for `route_tracker` in configuration
|
|
12
|
+
* Improvement: Better error handling when Redis is not available (defaults to NullStore with a warning)
|
|
13
|
+
* Improvement: Updates to `lib/coverband/utils/lines_classifier.rb` to better handle `:nocov:` markers
|
|
14
|
+
* Docs: Added `agents.md` for AI contributor guidelines
|
|
15
|
+
* Docs: Added `docs/mcp_security.md`
|
|
16
|
+
* Fix: Logging to `$stdout` instead of `STDOUT` to avoid warnings
|
|
17
|
+
* Fix: Added GitHub Issue templates and Dependabot config
|
|
18
|
+
|
|
1
19
|
### Coverband 6.1.6
|
|
2
20
|
|
|
3
21
|
* Check for Rails::Engine - Stephen Wetzel
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"./lib/coverband/integrations/resque.rb":{"first_updated_at":1768697779,"last_updated_at":1768697779,"file_hash":"977366ad12b0f837e4cc3daf56f0ca80","data":[null,null,1,0,0,null,null,1,0,0,0,0,null,null,1,1,1,0,null,0,null,null,null,null,1,0,0,0,null,0,null,0,0,null,null,1,null]},"./lib/coverband/reporters/web.rb":{"first_updated_at":1768697779,"last_updated_at":1768697779,"file_hash":"2787678b2bc7efcac5241a468cb46153","data":[null,null,1,1,null,null,1,null,0,null,null,1,1,1,1,null,1,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,1,0,0,null,null,null,null,1,0,null,null,0,0,null,0,null,null,1,0,0,null,null,1,0,null,0,null,0,0,0,0,0,0,0,0,0,null,0,null,null,null,null,0,0,0,null,0,null,0,null,0,null,null,0,null,0,null,0,null,0,null,0,null,0,null,0,null,0,null,0,null,0,null,0,null,null,null,null,null,1,0,0,0,0,null,null,null,null,null,0,0,null,null,null,1,0,null,null,null,null,null,1,0,null,null,null,0,0,null,null,null,null,null,1,0,0,null,null,1,0,0,null,0,null,null,null,0,null,null,1,0,null,null,1,0,null,null,1,0,null,null,null,null,null,null,1,0,0,null,null,null,null,null,1,0,0,0,null,0,null,0,null,null,1,0,0,0,0,null,0,null,0,null,null,1,0,0,0,null,0,null,0,null,null,1,0,0,0,0,null,0,null,0,null,null,1,null,1,null,0,null,0,0,null,null,null,null,null,null,null,null,null,null,1,0,null,null,null,null]},"./lib/coverband/utils/html_formatter.rb":{"first_updated_at":1768697779,"last_updated_at":1768697779,"file_hash":"8617750f352ca404c391010aabf5eb02","data":[null,null,1,1,1,1,1,null,null,null,null,null,1,1,1,1,null,1,0,0,0,0,0,null,null,1,0,null,null,1,0,null,null,1,0,null,null,1,0,null,null,1,0,null,0,0,null,0,null,null,null,1,null,1,0,null,null,1,0,0,null,null,0,0,null,null,null,1,0,null,null,1,0,null,null,null,1,0,null,null,1,0,null,null,1,0,null,0,0,0,null,null,1,0,null,null,1,0,null,null,1,0,0,0,0,0,null,null,1,0,null,null,null,1,0,null,0,null,null,null,1,0,null,null,null,0,null,0,null,null,1,0,0,0,0,0,0,null,0,null,null,null,1,0,0,0,0,null,0,null,null,null,1,0,0,null,0,null,null,null,null,1,0,null,null,1,0,0,null,0,null,null,null,1,0,null,null,1,0,0,null,null,1,0,0,null,0,0,null,null,null,null,null]},"./lib/coverband/utils/result.rb":{"first_updated_at":1768697779,"last_updated_at":1768697779,"file_hash":"ff599c81f41c81e32631b763a200528c","data":[null,null,1,1,null,null,null,null,null,null,null,null,1,1,1,1,null,null,1,null,null,1,1,null,1,null,1,1,null,null,null,1,0,null,0,0,null,null,null,null,1,0,null,null,null,1,0,null,null,null,null,1,0,null,0,0,0,0,null,null,null,null,null,null,0,null,null,null,null]},"./lib/coverband/utils/file_list.rb":{"first_updated_at":1768697779,"last_updated_at":1768697779,"file_hash":"fd392626f49763a4a541c7925509ef49","data":[null,null,null,null,null,null,null,null,null,1,1,1,null,1,0,null,0,null,null,null,1,0,null,0,null,null,null,1,0,null,0,null,null,null,1,0,null,0,null,null,null,null,1,0,null,null,null,1,0,null,null,null,null,1,0,null,0,null,null,null,null,1,0,null,null,null,null,1,0,null,0,null,null,1,0,null,null,null,null]},"./lib/coverband/utils/source_file.rb":{"first_updated_at":1768697779,"last_updated_at":1768697779,"file_hash":"fce22b672513bddebaf353ff73650db6","data":[null,null,null,null,null,null,null,null,null,1,1,1,null,null,null,null,null,null,1,null,1,null,1,null,1,null,1,null,1,null,null,1,1,1,null,1,0,0,0,null,0,0,0,0,0,null,null,null,1,0,null,null,null,1,0,null,null,null,1,0,null,null,null,1,0,null,null,null,null,1,0,null,null,null,null,1,0,0,0,0,null,null,null,null,1,null,1,null,1,null,null,1,null,1,null,1,1,null,1,0,0,0,0,0,0,0,0,0,null,null,0,0,0,null,null,null,1,0,0,null,0,null,null,null,1,0,null,null,null,1,null,null,0,null,1,null,null,null,1,0,null,1,null,1,0,null,0,0,null,null,0,0,null,null,null,0,null,null,null,1,0,null,null,null,1,0,null,null,null,1,0,null,0,null,null,0,null,null,1,0,null,null,1,0,null,0,null,null,1,0,null,null,1,0,0,null,null,null,1,0,null,null,null,1,0,null,null,1,0,null,null,1,0,null,null,1,0,null,null,null,null,1,0,null,null,null,null,1,0,null,null,null,1,0,null,null,null,1,0,null,null,null,null,1,0,null,0,0,0,0,0,0,null,null,null,null,null,null,null,1,0,null,null,1,0,null,null,1,null,null,null,1,0,0,null,null,null,null]},"./lib/coverband/utils/lines_classifier.rb":{"first_updated_at":1768697779,"last_updated_at":1768697779,"file_hash":"0edac53af03ce933e33845345200e4db","data":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,1,1,1,1,1,null,1,1,1,null,1,0,null,null,1,0,null,null,0,null,null,1,0,null,null,0,null,null,1,0,null,0,0,0,0,0,0,null,0,null,null,null,null,null,null]},"./lib/coverband/utils/results.rb":{"first_updated_at":1768697779,"last_updated_at":1768697779,"file_hash":"081416e6d4a6a505e75ad15e6d574a07","data":[null,null,null,null,null,1,1,1,1,null,1,0,0,0,null,null,1,0,null,0,0,0,null,0,null,null,1,0,null,0,0,null,0,null,0,null,0,0,null,null,1,0,null,0,0,null,0,null,0,null,0,null,null,1,0,null,0,0,0,null,0,null,null,1,0,0,null,0,null,null,null,1,0,null,null,null,1,0,null,null,1,0,null,null,1,0,null,null,1,null,1,0,null,null,1,0,null,null,1,0,null,null,1,0,null,null,null,null,null,null,null,1,0,null,0,null,null,null,null]},"./lib/coverband/reporters/html_report.rb":{"first_updated_at":1768697779,"last_updated_at":1768697779,"file_hash":"1eb64bf06752d4a576109af8bcec6c69","data":[null,null,1,1,1,1,null,null,1,0,0,null,0,0,0,null,0,null,0,0,null,0,null,null,null,1,0,null,null,null,null,1,0,null,null,1,0,null,null,1,null,1,0,null,null,null,null,null,1,0,null,null,null,null,null,null,null]},"./lib/coverband/reporters/json_report.rb":{"first_updated_at":1768697779,"last_updated_at":1768697779,"file_hash":"4c3d2aa6266411fd5aa23a2e87f4c8cf","data":[null,null,null,null,1,1,1,1,null,null,1,0,0,0,0,0,0,0,0,null,0,null,0,0,null,0,null,null,null,1,0,null,null,1,0,0,null,null,null,null,null,0,0,null,null,null,null,null,null,0,0,null,null,null,null,null,null,0,null,null,1,null,1,0,0,0,0,0,0,null,0,null,null,null,1,0,null,0,0,null,0,null,null,null,null,0,0,0,0,0,0,null,0,0,0,null,null,null,null,0,null,null,null,null,null,null,0,0,0,0,0,0,null,0,null,null,1,null,0,null,null,null,null,null,null,null,null,null,1,0,0,null,0,null,null,null,null,null,null,null,null,null,null,0,0,null,null,null,null,null]},"./test/unique_files.rb":{"first_updated_at":1768697779,"last_updated_at":1768697779,"file_hash":"80447d67747af66d3792f3f9ec0be166","data":[null,null,1,1,1,null,1,null,1,0,0,0,0,0,0,0,null,0,0,0,null,0,0,0,null,null,1,0,0,0,null,null,1,0,null,null,1,1,0,null,null]}}
|
data/coverband.gemspec
CHANGED
|
@@ -31,6 +31,7 @@ Gem::Specification.new do |spec|
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
spec.add_development_dependency "benchmark-ips"
|
|
34
|
+
spec.add_development_dependency "benchmark" # Ruby 4.0+ requires explicit dependency
|
|
34
35
|
spec.add_development_dependency "capybara"
|
|
35
36
|
spec.add_development_dependency "m"
|
|
36
37
|
spec.add_development_dependency "memory_profiler"
|
|
@@ -38,7 +39,7 @@ Gem::Specification.new do |spec|
|
|
|
38
39
|
# note: we are also adding 'spy' as mocha doesn't want us to spy on redis calls...
|
|
39
40
|
spec.add_development_dependency "spy"
|
|
40
41
|
# ^^^ probably need a large test cleanup refactor
|
|
41
|
-
spec.add_development_dependency "minitest"
|
|
42
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
|
42
43
|
spec.add_development_dependency "minitest-fork_executor"
|
|
43
44
|
spec.add_development_dependency "minitest-stub-const"
|
|
44
45
|
spec.add_development_dependency "mocha"
|
|
@@ -55,6 +56,7 @@ Gem::Specification.new do |spec|
|
|
|
55
56
|
# spec.add_development_dependency "minitest-profile"
|
|
56
57
|
spec.add_development_dependency "webmock"
|
|
57
58
|
spec.add_development_dependency "dalli" # Default memcached adapter
|
|
59
|
+
spec.add_development_dependency "mcp" # For MCP server support testing
|
|
58
60
|
|
|
59
61
|
# TODO: Remove when other production adapters exist
|
|
60
62
|
# because the default configuration of redis store, we really do require
|
|
@@ -13,7 +13,7 @@ module Coverband
|
|
|
13
13
|
TITLE = "Routes"
|
|
14
14
|
|
|
15
15
|
def initialize(options = {})
|
|
16
|
-
if Rails
|
|
16
|
+
if defined?(Rails) && Rails.respond_to?(:version) && Gem::Version.new(Rails.version) < Gem::Version.new("7.1.0")
|
|
17
17
|
require_relative "../utils/rails6_ext"
|
|
18
18
|
end
|
|
19
19
|
|
|
@@ -64,23 +64,14 @@ module Coverband
|
|
|
64
64
|
views = redis_store.hgetall(tracker_key)
|
|
65
65
|
normalized_views = {}
|
|
66
66
|
views.each_pair do |view, time|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
end
|
|
70
|
-
normalized_views[view] = time
|
|
67
|
+
normalized_view = normalize_path(view)
|
|
68
|
+
normalized_views[normalized_view] = time
|
|
71
69
|
end
|
|
72
70
|
normalized_views
|
|
73
71
|
end
|
|
74
72
|
|
|
75
73
|
def all_keys
|
|
76
|
-
|
|
77
|
-
target.each do |view|
|
|
78
|
-
roots.each do |root|
|
|
79
|
-
view = view.gsub(root, "")
|
|
80
|
-
end
|
|
81
|
-
all_views << view
|
|
82
|
-
end
|
|
83
|
-
all_views.uniq
|
|
74
|
+
target.map { |view| normalize_path(view) }.uniq
|
|
84
75
|
end
|
|
85
76
|
|
|
86
77
|
def unused_keys(used_views = nil)
|
|
@@ -106,9 +97,26 @@ module Coverband
|
|
|
106
97
|
@ignore_patterns.none? { |pattern| file.match?(pattern) }
|
|
107
98
|
end
|
|
108
99
|
|
|
100
|
+
def normalize_path(view)
|
|
101
|
+
normalized = view.dup
|
|
102
|
+
original_length = normalized.length
|
|
103
|
+
|
|
104
|
+
roots.each do |root|
|
|
105
|
+
normalized = normalized.gsub(root, "")
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Only remove leading slash if we actually modified the path by removing a root
|
|
109
|
+
# This ensures consistent relative paths after root removal
|
|
110
|
+
if normalized.length < original_length
|
|
111
|
+
normalized.sub(/^\//, "")
|
|
112
|
+
else
|
|
113
|
+
normalized
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
109
117
|
def concrete_target
|
|
110
118
|
if defined?(Rails.application)
|
|
111
|
-
Dir.glob("#{@project_directory}
|
|
119
|
+
Dir.glob("#{@project_directory}/{,packs,engines/*}/app/{views,components}/**/*.html.{erb,haml,slim}")
|
|
112
120
|
else
|
|
113
121
|
[]
|
|
114
122
|
end
|
|
@@ -14,13 +14,14 @@ module Coverband
|
|
|
14
14
|
:view_tracker, :defer_eager_loading_data,
|
|
15
15
|
:track_routes, :track_redirect_routes, :route_tracker,
|
|
16
16
|
:track_translations, :translations_tracker,
|
|
17
|
-
:trackers, :csp_policy, :hide_settings
|
|
17
|
+
:trackers, :csp_policy, :hide_settings,
|
|
18
|
+
:mcp_enabled
|
|
18
19
|
|
|
19
20
|
attr_writer :logger, :s3_region, :s3_bucket, :s3_access_key_id,
|
|
20
21
|
:s3_secret_access_key, :password, :api_key, :service_url, :coverband_timeout, :service_dev_mode,
|
|
21
22
|
:service_test_mode, :process_type, :track_views, :redis_url,
|
|
22
23
|
:background_reporting_sleep_seconds, :reporting_wiggle,
|
|
23
|
-
:send_deferred_eager_loading_data, :paged_reporting
|
|
24
|
+
:send_deferred_eager_loading_data, :paged_reporting, :mcp_allowed_environments, :mcp_password
|
|
24
25
|
|
|
25
26
|
attr_reader :track_gems, :ignore
|
|
26
27
|
|
|
@@ -31,19 +32,19 @@ module Coverband
|
|
|
31
32
|
# * Perhaps detect heroku deployment ENV var opposed to tasks?
|
|
32
33
|
#####
|
|
33
34
|
IGNORE_TASKS = ["coverband:clear",
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
35
|
+
"coverband:coverage",
|
|
36
|
+
"coverband:coverage_server",
|
|
37
|
+
"assets:precompile",
|
|
38
|
+
"webpacker:compile",
|
|
39
|
+
"db:version",
|
|
40
|
+
"db:create",
|
|
41
|
+
"db:drop",
|
|
42
|
+
"db:seed",
|
|
43
|
+
"db:setup",
|
|
44
|
+
"db:test:prepare",
|
|
45
|
+
"db:structure:dump",
|
|
46
|
+
"db:structure:load",
|
|
47
|
+
"db:version"]
|
|
47
48
|
|
|
48
49
|
# Heroku when building assets runs code from a dynamic directory
|
|
49
50
|
# /tmp was added to avoid coverage from /tmp/build directories during
|
|
@@ -91,6 +92,11 @@ module Coverband
|
|
|
91
92
|
@csp_policy = false
|
|
92
93
|
@hide_settings = false
|
|
93
94
|
|
|
95
|
+
# MCP (Model Context Protocol) security settings
|
|
96
|
+
@mcp_enabled = false
|
|
97
|
+
@mcp_password = nil
|
|
98
|
+
@mcp_allowed_environments = %w[development test]
|
|
99
|
+
|
|
94
100
|
# coverband service settings
|
|
95
101
|
@api_key = nil
|
|
96
102
|
@service_url = nil
|
|
@@ -144,14 +150,40 @@ module Coverband
|
|
|
144
150
|
@logger ||= if defined?(Rails.logger) && Rails.logger
|
|
145
151
|
Rails.logger
|
|
146
152
|
else
|
|
147
|
-
Logger.new(
|
|
153
|
+
Logger.new($stdout)
|
|
148
154
|
end
|
|
149
155
|
end
|
|
150
156
|
|
|
157
|
+
# Alias for backward compatibility - track_key uses :routes_tracker symbol
|
|
158
|
+
def routes_tracker
|
|
159
|
+
route_tracker
|
|
160
|
+
end
|
|
161
|
+
|
|
151
162
|
def password
|
|
152
163
|
@password || ENV["COVERBAND_PASSWORD"]
|
|
153
164
|
end
|
|
154
165
|
|
|
166
|
+
def mcp_enabled?
|
|
167
|
+
# MCP is disabled by default and explicitly controlled
|
|
168
|
+
return false unless @mcp_enabled
|
|
169
|
+
|
|
170
|
+
# Check if current environment is allowed
|
|
171
|
+
current_env = (defined?(Rails) && Rails.respond_to?(:env) && Rails.env) ||
|
|
172
|
+
ENV["RAILS_ENV"] ||
|
|
173
|
+
ENV["RACK_ENV"] ||
|
|
174
|
+
"development"
|
|
175
|
+
|
|
176
|
+
mcp_allowed_environments.include?(current_env.to_s)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def mcp_password
|
|
180
|
+
@mcp_password || ENV["COVERBAND_MCP_PASSWORD"]
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def mcp_allowed_environments
|
|
184
|
+
@mcp_allowed_environments || %w[development test]
|
|
185
|
+
end
|
|
186
|
+
|
|
155
187
|
# The adjustments here either protect the redis or service from being overloaded
|
|
156
188
|
# the tradeoff being the delay in when reporting data is available
|
|
157
189
|
# if running your own redis increasing this number reduces load on the redis CPU
|
|
@@ -180,7 +212,14 @@ module Coverband
|
|
|
180
212
|
require "coverband/adapters/web_service_store"
|
|
181
213
|
Coverband::Adapters::WebServiceStore.new(service_url)
|
|
182
214
|
else
|
|
183
|
-
|
|
215
|
+
begin
|
|
216
|
+
Coverband::Adapters::RedisStore.new(Redis.new(url: redis_url), redis_store_options)
|
|
217
|
+
rescue Redis::CannotConnectError => error
|
|
218
|
+
logger.info "Redis is not available (#{error}), defaulting to NullStore"
|
|
219
|
+
logger.info "If this is intended, please explicitly configure your store: config.store = Coverband::Adapters::FileStore.new('log/coverage')"
|
|
220
|
+
require "coverband/adapters/null_store"
|
|
221
|
+
Coverband::Adapters::NullStore.new
|
|
222
|
+
end
|
|
184
223
|
end
|
|
185
224
|
end
|
|
186
225
|
|
|
@@ -242,7 +281,7 @@ module Coverband
|
|
|
242
281
|
@all_root_patterns ||= all_root_paths.map { |path| /^#{path}/ }.freeze
|
|
243
282
|
end
|
|
244
283
|
|
|
245
|
-
SKIPPED_SETTINGS = %w[@s3_secret_access_key @store @api_key @password]
|
|
284
|
+
SKIPPED_SETTINGS = %w[@s3_secret_access_key @store @api_key @password @mcp_password]
|
|
246
285
|
def to_h
|
|
247
286
|
instance_variables
|
|
248
287
|
.each_with_object({}) do |var, hash|
|