Commit 12350a4
authored
feat(eval): add evaluation harness for rule efficacy measurement (#158)
* feat(eval): add evaluation harness module for rule efficacy testing
Add core evaluation types and logic:
- EvalCase, EvalResult for test case representation
- RuleMetrics with precision/recall/F1 calculation
- EvalSummary aggregating results across cases
- EvalManifest for YAML manifest parsing
- evaluate_case() and evaluate_manifest() functions
- Output formatters: JSON, CSV, Markdown
This enables measuring validation rule effectiveness against labeled
test cases, supporting data-driven rule development.
Part of #111
* feat(cli): add 'agnix eval' subcommand for evaluation harness
Add CLI subcommand to run evaluation manifests:
- --format option: markdown (default), json, csv
- --filter option: filter cases by rule prefix
- --verbose option: show per-case pass/fail details
- Exit code 1 on any failing cases
Usage:
agnix eval tests/eval/eval.yaml
agnix eval tests/eval/eval.yaml --format json
agnix eval tests/eval/eval.yaml --filter "MCP-" --verbose
Part of #111
* test(eval): add initial evaluation dataset with 39 test cases
Create evaluation manifest covering all rule families:
- AS-*, CC-SK-*: Skill validation rules (13 cases)
- MCP-*: MCP tool validation rules (8 cases)
- AGM-*: AGENTS.md rules (6 cases)
- XP-*: Cross-platform rules (5 cases)
- XML-*: XML validation rules (4 cases)
- REF-*: Reference/import rules (3 cases)
All 39 cases pass with 100% precision/recall.
Part of #111
* docs(eval): add evaluation harness documentation
Document the evaluation harness feature:
- Quick start examples
- Manifest format specification
- Metrics explanation (TP, FP, FN, precision, recall, F1)
- Output format examples (markdown, JSON, CSV)
- Usage guide for regression testing and rule development
Part of #111
* fix: add path traversal protection and comprehensive tests
- Add validate_path_within_base() to prevent path traversal attacks
- Add EvalError::PathTraversal variant for security errors
- Add tests for error paths (file not found, invalid YAML)
- Add tests for filter logic with various scenarios
- Add tests for evaluate_manifest_file entry point
- Add tests for path traversal detection
- Add tests for Display trait and empty results edge case
Security: Validates that manifest file paths stay within base directory
* fix(security): harden path traversal protection
- Reject absolute paths explicitly (only relative paths allowed)
- Reject paths containing .. segments before joining (defense-in-depth)
- Fail validation when canonicalization fails (no fallback to non-canonical)
- Add explicit test for absolute path rejection
- Strengthen test assertions to explicitly verify path-traversal detection
Security: Addresses edge cases with non-existent malicious paths and
platform-specific path behaviors.
* fix(security): allow relative paths with parent refs within repo
The previous security model was too strict, rejecting any path with ..
segments. This made the evaluation harness unusable for manifests in
subdirectories that reference sibling directories (e.g., tests/eval/
referencing ../fixtures/).
New security model:
- Reject absolute paths (prevents /etc/passwd access)
- Allow relative paths with .. (enables ../fixtures patterns)
- Require file to exist (canonicalization verifies)
This is still secure because:
1. Absolute paths are blocked
2. Non-existent files fail validation
3. Symlinks are resolved to real targets
Add test for relative paths with parent directory references.
* docs: add eval command to README and CHANGELOG
- Add agnix eval example to Quick Start section
- Add comprehensive changelog entry for evaluation harness feature
* fix: address review feedback - path traversal and filter logic
Security (Critical):
- Add canonical base directory check to prevent path traversal
- Return canonical path to prevent TOCTOU vulnerabilities
- Move eval.yaml to tests/ to avoid ../fixtures paths
Filter logic (High):
- Include cases with empty expected to detect FPs on clean files
- Use starts_with for filter matching (per CLI help text)
Tests:
- Update path traversal tests for stricter security
- Add test_relative_path_within_base_dir_allowed
- Update test_relative_path_escaping_base_dir_blocked
Docs:
- Update paths from tests/eval/eval.yaml to tests/eval.yaml1 parent dd61f9d commit 12350a4
7 files changed
Lines changed: 1575 additions & 0 deletions
File tree
- crates
- agnix-cli/src
- agnix-core/src
- knowledge-base
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
71 | 71 | | |
72 | 72 | | |
73 | 73 | | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
74 | 83 | | |
75 | 84 | | |
76 | 85 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
78 | 81 | | |
79 | 82 | | |
80 | 83 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
10 | 11 | | |
11 | 12 | | |
12 | 13 | | |
| |||
95 | 96 | | |
96 | 97 | | |
97 | 98 | | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
98 | 118 | | |
99 | 119 | | |
100 | 120 | | |
| |||
110 | 130 | | |
111 | 131 | | |
112 | 132 | | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
113 | 151 | | |
114 | 152 | | |
115 | 153 | | |
| |||
118 | 156 | | |
119 | 157 | | |
120 | 158 | | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
121 | 165 | | |
122 | 166 | | |
123 | 167 | | |
| |||
373 | 417 | | |
374 | 418 | | |
375 | 419 | | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
0 commit comments