|
| 1 | +# Code Review Agent — Architecture Design |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +基于 tRPC-Agent SDK 的自动化代码评审 Agent,集成 Skills、沙箱执行、SQLite 存储,提供端到端的代码审查流水线。 |
| 6 | + |
| 7 | +**核心理念**:将代码评审拆解为独立的流水线阶段,每个阶段可独立测试、替换和扩展。 |
| 8 | + |
| 9 | +## Architecture |
| 10 | + |
| 11 | +### Pipeline (8-stage linear workflow) |
| 12 | + |
| 13 | +``` |
| 14 | + ┌──────────┐ ┌──────────┐ ┌───────────────┐ ┌──────────┐ |
| 15 | + │ 1. Read │ → │ 2. Parse │ → │ 3. Filter │ → │ 4. Scan │ |
| 16 | + │ diff │ │ diff │ │ chain │ │ code │ |
| 17 | + └──────────┘ └──────────┘ └───────────────┘ └──────────┘ |
| 18 | + │ │ │ │ |
| 19 | + ▼ ▼ ▼ ▼ |
| 20 | + --diff-file unified diff SafetyFilter x4 10 scanners |
| 21 | + --repo-path DiffFile[] deny/allow/needs Finding[] |
| 22 | + --stdin DiffHunk[] _human_review |
| 23 | + |
| 24 | + ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ |
| 25 | + │ 5. Sand- │ → │ 6. Dedup │ → │ 7. Report│ → │ 8. Store │ |
| 26 | + │ box │ │ +Redact │ │ gen │ │ DB │ |
| 27 | + └──────────┘ └──────────┘ └──────────┘ └──────────┘ |
| 28 | + │ │ │ │ |
| 29 | + ▼ ▼ ▼ ▼ |
| 30 | + Fake/Local/ fingerprint JSON + MD SQLite |
| 31 | + Workspace + 3-tier conf + SARIF + schema |
| 32 | + SandboxRun + 12 patterns ReviewReport versioning |
| 33 | +``` |
| 34 | + |
| 35 | +### Module Map |
| 36 | + |
| 37 | +| Module | File | Lines | Responsibility | |
| 38 | +|--------|------|-------|----------------| |
| 39 | +| Types | `pipeline/types.py` | ~117 | Data contracts (Finding, DiffFile, SandboxRun, etc.) | |
| 40 | +| Config | `pipeline/config.py` | ~52 | Pipeline configuration with defaults and overrides | |
| 41 | +| Diff Parser | `pipeline/diff_parser.py` | ~185 | Unified diff parsing, changed line extraction | |
| 42 | +| Filter Chain | `pipeline/filter_chain.py` | ~135 | Safety filter chain with policy-as-code support | |
| 43 | +| Scanners | `pipeline/scanners.py` | ~340 | 10 pattern-matching scanners with per-category thresholds | |
| 44 | +| Sandbox | `pipeline/sandbox.py` | ~220 | Fake/Local/Workspace sandbox abstraction | |
| 45 | +| Dedup | `pipeline/dedup.py` | ~110 | Fingerprint-based dedup with 3-tier confidence | |
| 46 | +| Redaction | `pipeline/redaction.py` | ~82 | 12 regex patterns for secret/credential redaction | |
| 47 | +| AST Analyzer | `pipeline/ast_analyzer.py` | ~230 | Python AST + JS/TS regex taint analysis | |
| 48 | +| Report | `pipeline/report.py` | ~210 | JSON + Markdown report generation | |
| 49 | +| SARIF Output | `pipeline/sarif_output.py` | ~120 | SARIF v2.1.0 for GitHub Code Scanning integration | |
| 50 | +| Telemetry | `pipeline/telemetry.py` | ~78 | Timing and cost collection | |
| 51 | +| Storage/Models | `storage/models.py` | ~72 | DB record dataclasses | |
| 52 | +| Storage/DAO | `storage/dao.py` | ~320 | SQLite CRUD with schema versioning and migrations | |
| 53 | +| Agent | `agent/agent.py` | ~50 | LlmAgent wrapper for tRPC-Agent framework | |
| 54 | +| Skill | `skills/code-review/SKILL.md` | ~43 | Skill definition with rules and scripts | |
| 55 | +| CLI | `run_review.py` | ~360 | argparse CLI entry point | |
| 56 | +| Fixture Eval | `evaluate_fixtures.py` | ~200 | Precision/recall/F1 evaluation framework | |
| 57 | + |
| 58 | +## Key Design Decisions |
| 59 | + |
| 60 | +### 1. Pattern-Match Scanners vs ML-based Analysis |
| 61 | + |
| 62 | +**Decision**: Use regex-based pattern matching with AST enhancement. |
| 63 | +**Rationale**: |
| 64 | +- Deterministic and fast — no API calls, no rate limits |
| 65 | +- Easy to audit and extend — adding a rule is one tuple |
| 66 | +- AST analysis adds semantic understanding without complexity |
| 67 | +- 10 scanners covering security, async, resources, DB, tests, secrets, and code quality |
| 68 | + |
| 69 | +### 2. Three-Tier Confidence System |
| 70 | + |
| 71 | +**Decision**: Classify findings into high (≥0.8), warning (≥0.55), needs_human_review (<0.55). |
| 72 | +**Rationale**: |
| 73 | +- Mirrors real production review workflows |
| 74 | +- High-confidence findings can auto-block merges |
| 75 | +- Warning tier gives reviewers a prioritized list |
| 76 | +- Low-confidence items don't create noise in automated mode |
| 77 | +- Per-scanner threshold overrides allow fine-tuning |
| 78 | + |
| 79 | +### 3. Multi-Runtime Sandbox Abstraction |
| 80 | + |
| 81 | +**Decision**: SandboxRunner ABC with Fake/Local/Workspace implementations. |
| 82 | +**Rationale**: |
| 83 | +- Fake runner enables complete CI testing without Docker |
| 84 | +- Local runner for development with subprocess isolation |
| 85 | +- Workspace runner for production (Container/Cube/E2B) |
| 86 | +- Trigger-based edge case simulation in fake mode (timeout, large output, secrets) |
| 87 | + |
| 88 | +### 4. Policy-as-Code Filter Governance |
| 89 | + |
| 90 | +**Decision**: Externalize filter rules to `filter_policy.json`. |
| 91 | +**Rationale**: |
| 92 | +- Rules updateable without code changes |
| 93 | +- Auditable — filter decisions logged to DB |
| 94 | +- Extensible — add new patterns without redeploying |
| 95 | +- Pre-block high-risk scripts before sandbox execution |
| 96 | + |
| 97 | +### 5. SQLite with Schema Versioning |
| 98 | + |
| 99 | +**Decision**: Use SQLite with COLUMN_MIGRATIONS dict for schema evolution. |
| 100 | +**Rationale**: |
| 101 | +- Zero-dependency storage |
| 102 | +- Schema version table tracks current state |
| 103 | +- Column migrations apply incrementally (v1→v2→v3→v4) |
| 104 | +- WAL mode for concurrent reads |
| 105 | +- Forward-compatible: new columns have defaults |
| 106 | + |
| 107 | +### 6. Multi-Format Output (JSON + MD + SARIF) |
| 108 | + |
| 109 | +**Decision**: Generate three output formats from the same ReviewReport. |
| 110 | +**Rationale**: |
| 111 | +- JSON: machine-readable, API integration |
| 112 | +- Markdown: human-readable, PR comments |
| 113 | +- SARIF v2.1.0: GitHub Code Scanning, Azure DevOps integration |
| 114 | + |
| 115 | +## Failure Modes and Mitigations |
| 116 | + |
| 117 | +| Failure Mode | Detection | Mitigation | |
| 118 | +|-------------|-----------|------------| |
| 119 | +| Empty diff | Stage 2: 0 files parsed → early exit | No crash, clean exit 0 | |
| 120 | +| Malicious diff content | Stage 3: FilterChain evaluation | Block before sandbox execution | |
| 121 | +| Sandbox timeout | Stage 5: timeout_seconds limit | SandboxRun.timed_out=True, pipeline continues | |
| 122 | +| Sandbox crash | Stage 5: exception handling | SandboxRun.error, pipeline continues | |
| 123 | +| Output too large | Stage 5: max_output_bytes limit | Truncation with marker | |
| 124 | +| DB connection failure | Stage 8: exception handling | Report still written to disk before DB | |
| 125 | +| Scanner regex catastrophic backtracking | Per-scanner execution, timeout | Individual scanner failure doesn't crash others | |
| 126 | + |
| 127 | +## Trade-offs |
| 128 | + |
| 129 | +| Trade-off | Choice | Why | |
| 130 | +|-----------|--------|-----| |
| 131 | +| Speed vs Accuracy | Prioritized speed | Regex scanners are O(n) per pattern; real LLM review can be layered on top | |
| 132 | +| Coverage vs Precision | Balanced (3-tier) | High-confidence blocking + human review for edge cases | |
| 133 | +| Simplicity vs Features | Leaned toward feature completeness | 10 scanners, 3 sandbox modes, 3 output formats, but each module is simple | |
| 134 | +| Testing vs Implementation | Heavy testing investment | 205 tests across 15 files → refactoring confidence | |
| 135 | + |
| 136 | +## Data Flow |
| 137 | + |
| 138 | +``` |
| 139 | +diff_text (str) |
| 140 | + → parse_diff() → DiffFile[] |
| 141 | + → FilterChain.evaluate() → FilterDecision |
| 142 | + → run_scanners() × N → Finding[] |
| 143 | + → FakeSandboxRunner.run() → SandboxRun |
| 144 | + → deduplicate() → Finding[] (deduped) |
| 145 | + → separate_by_tiers() → {high, warning, needs_human_review} |
| 146 | + → redact_finding_evidence() → Finding[] (redacted) |
| 147 | + → generate_json_report() → JSON string |
| 148 | + → generate_md_report() → Markdown string |
| 149 | + → generate_sarif() → SARIF JSON string |
| 150 | + → ReviewDatabase.insert_*() → SQLite rows |
| 151 | +``` |
| 152 | + |
| 153 | +## Extensibility |
| 154 | + |
| 155 | +1. **Add a scanner**: Create function `scan_xxx(diff_file) → list[Finding]`, add to `_SCANNERS` dict |
| 156 | +2. **Add a filter**: Add to `filter_policy.json` or create SafetyFilter in code |
| 157 | +3. **Add a sandbox**: Implement `SandboxRunner` ABC, register in `create_sandbox_runner()` |
| 158 | +4. **Add an output format**: Create `generate_xxx(report) → str`, call from `run_review.py` |
| 159 | +5. **Schema migration**: Add entry to `COLUMN_MIGRATIONS` dict, increment `SCHEMA_VERSION` |
0 commit comments