Skip to content

Commit f625038

Browse files
feat(security-firm): multi-agent repo scanner (#6)
* feat(security-firm): add multi-agent repo scanner — 4 agents, 1M tokens each New module src/firm/security_firm/ with: - 4 agents: claude-opus-4.6 (director), gpt-5.4 (scanner), gpt-5.3-codex (analyzer), gemini-3.1-pro (reporter) - All via copilot-pro provider, 1M token budget each - FindingsDB: SQLite-backed with SHA-256 dedup - 10 repo scanning tools (tree, grep_secrets, dependency_audit, config_scan, semgrep, git_history, etc.) - 4-phase pipeline: Map → Scan (3 agents parallel) → Triage → Report - Markdown report generator with risk scoring + CWE links - 56 tests passing (agents, findings, tools, report, pipeline, factory) - Zero ruff lint errors * chore: remove AI disclaimers from security_firm module
1 parent b7f5721 commit f625038

11 files changed

Lines changed: 2480 additions & 22 deletions

File tree

docs/TUTORIAL.md

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -782,7 +782,7 @@ cto = create_llm_agent(firm, "CTO", provider_name="copilot-pro",
782782

783783
# Dev senior = GPT-5.3 — dernière gen, très performant
784784
senior = create_llm_agent(firm, "Senior", provider_name="copilot-pro",
785-
model="gpt-5.3", authority=0.7)
785+
model="gpt-5.4", authority=0.7)
786786

787787
# Reviewer = Claude Sonnet 4.6 — rapide et précis pour la review
788788
reviewer = create_llm_agent(firm, "Reviewer", provider_name="copilot-pro",
@@ -811,7 +811,6 @@ for agent in [cto, senior, reviewer, junior, coder, architect]:
811811
```
812812
CTO | copilot-pro | claude-opus-4.6
813813
Senior | copilot-pro | gpt-5.4
814-
Senior | copilot-pro | gpt-5.3
815814
Reviewer | copilot-pro | claude-sonnet-4.6
816815
Junior | copilot-pro | claude-haiku-4.5
817816
Coder | copilot-pro | gpt-5.3-codex
@@ -820,18 +819,18 @@ Architect | copilot-pro | gemini-3.1-pro
820819

821820
### Récapitulatif : quel provider choisir ?
822821

823-
| Situation | Provider recommandé | Modèle | Coût |
824-
| ------------------------------------------ | -------------------: | -------------------------------------------- | ------------------------- |
825-
| **Copilot Pro** — tâches complexes | `copilot-pro` | `claude-opus-4.6` | Inclus dans l'abo |
826-
| **Copilot Pro** — usage général | `copilot-pro` | `claude-sonnet-4.6` ou `gpt-5.3/gpt-5.4` | Inclus |
827-
| **Copilot Pro** — code intensif | `copilot-pro` | `gpt-5.3-codex` | Inclus |
828-
| **Copilot Pro** — tâches simples | `copilot-pro` | `claude-haiku-4.5` ou `gpt-5-mini` | Inclus |
829-
| **Copilot Pro** — Google AI | `copilot-pro` | `gemini-3.1-pro` | Inclus |
830-
| Clé**Anthropic** directe | `claude` | `claude-sonnet-4` | $3 / $15 par 1M tokens |
831-
| Clé**OpenAI** directe | `gpt` | `gpt-4o` | $2.5 / $10 par 1M tokens |
832-
| **Gratuit** (Google) | `gemini` | `gemini-2.5-pro` | Gratuit (rate-limited) |
833-
| **Gratuit** (GitHub) | `copilot` | `gpt-4o` | Gratuit (rate-limited) |
834-
| Budget serré | `mistral` | `mistral-small-latest` | $0.2 / $0.6 par 1M tokens |
822+
| Situation | Provider recommandé | Modèle | Coût |
823+
| ------------------------------------------ | -------------------: | -------------------------------------- | ------------------------- |
824+
| **Copilot Pro** — tâches complexes | `copilot-pro` | `claude-opus-4.6` | Inclus dans l'abo |
825+
| **Copilot Pro** — usage général | `copilot-pro` | `claude-sonnet-4.6` ou `gpt-5.4` | Inclus |
826+
| **Copilot Pro** — code intensif | `copilot-pro` | `gpt-5.3-codex` | Inclus |
827+
| **Copilot Pro** — tâches simples | `copilot-pro` | `claude-haiku-4.5` ou `gpt-5-mini` | Inclus |
828+
| **Copilot Pro** — Google AI | `copilot-pro` | `gemini-3.1-pro` | Inclus |
829+
| Clé**Anthropic** directe | `claude` | `claude-sonnet-4` | $3 / $15 par 1M tokens |
830+
| Clé**OpenAI** directe | `gpt` | `gpt-4o` | $2.5 / $10 par 1M tokens |
831+
| **Gratuit** (Google) | `gemini` | `gemini-2.5-pro` | Gratuit (rate-limited) |
832+
| **Gratuit** (GitHub) | `copilot` | `gpt-4o` | Gratuit (rate-limited) |
833+
| Budget serré | `mistral` | `mistral-small-latest` | $0.2 / $0.6 par 1M tokens |
835834

836835
---
837836

@@ -1374,14 +1373,14 @@ else:
13741373

13751374
Le bridge MCP a été testé **sur ce repository** (`firm-protocol/src/firm`) :
13761375

1377-
| Étape | Résultat | Statut |
1378-
|-------|----------|--------|
1379-
| **Connexion MCP** | `143 outils` découverts via JSON-RPC ||
1380-
| **Création Firm** | Organisation `test-mcp-bridge` initialisée ||
1381-
| **ToolKit Security** | `10 outils` chargés (scan, sandbox, secrets…) ||
1382-
| **Appel MCP réel** | `firm_security_scan`**45 fichiers scannés**, 4 vulnérabilités HIGH dans `reputation.py` ||
1383-
| **Filtrage catégories** | memory (10) · a2a (8) · compliance (14) · delivery (6) ||
1384-
| **Extension agent** | `20 outils MCP` ajoutés au CTO (security + memory) ||
1376+
| Étape | Résultat | Statut |
1377+
| ------------------------------ | -------------------------------------------------------------------------------------------------------- | ------ |
1378+
| **Connexion MCP** | `143 outils` découverts via JSON-RPC | |
1379+
| **Création Firm** | Organisation `test-mcp-bridge` initialisée | |
1380+
| **ToolKit Security** | `10 outils` chargés (scan, sandbox, secrets…) | |
1381+
| **Appel MCP réel** | `firm_security_scan`**45 fichiers scannés**, 4 vulnérabilités HIGH dans `reputation.py` | |
1382+
| **Filtrage catégories** | memory (10) · a2a (8) · compliance (14) · delivery (6) | |
1383+
| **Extension agent** | `20 outils MCP` ajoutés au CTO (security + memory) | |
13851384

13861385
> **Conclusion :** Un agent FIRM connecté via `extend_agent_with_mcp(cto)` peut appeler
13871386
> nativement les 143 outils de l'écosystème MCP dans le cadre du système d'autorité FIRM.

examples/security_firm_demo.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#!/usr/bin/env python3
2+
"""Security Firm demo — scan a repository with 4 AI agents.
3+
4+
Usage:
5+
python examples/security_firm_demo.py /path/to/repo
6+
python examples/security_firm_demo.py https://github.com/org/repo
7+
8+
The script will:
9+
1. Clone (if URL) or open the repo
10+
2. Spin up 4 agents: security-director, code-scanner, static-analyzer,
11+
report-synthesizer
12+
3. Scan in parallel (code review + static analysis + architecture mapping)
13+
4. Triage and deduplicate findings
14+
5. Generate a Markdown report → saved to security-report-{name}.md
15+
16+
Requirements:
17+
- Copilot Pro JWT (COPILOT_JWT env var or cached token)
18+
- MCP server at http://127.0.0.1:8012 (optional but recommended)
19+
"""
20+
21+
from __future__ import annotations
22+
23+
import logging
24+
import sys
25+
import time
26+
from pathlib import Path
27+
28+
# ── Logging ─────────────────────────────────────────────────────────────────
29+
30+
logging.basicConfig(
31+
level=logging.INFO,
32+
format="%(asctime)s [%(levelname)s] %(name)s — %(message)s",
33+
datefmt="%H:%M:%S",
34+
)
35+
logger = logging.getLogger("security-firm")
36+
37+
38+
def main(repo_path: str) -> None:
39+
from firm.security_firm import create_security_firm
40+
41+
print("=" * 70)
42+
print(" FIRM Security Firm — Multi-Agent Repository Scanner")
43+
print("=" * 70)
44+
print()
45+
print(f" Target: {repo_path}")
46+
print(f" Agents: 4 (copilot-pro)")
47+
print(f" Models: claude-opus-4.6, gpt-5.4, gpt-5.3-codex, gemini-3.1-pro")
48+
print(f" Budget: 1,000,000 tokens per agent")
49+
print()
50+
51+
start = time.time()
52+
53+
# Create and run the pipeline
54+
ctx = create_security_firm(
55+
repo_path=repo_path,
56+
use_mcp=True,
57+
max_workers=3,
58+
)
59+
60+
pipeline = ctx["pipeline"]
61+
report = pipeline.run()
62+
63+
elapsed = time.time() - start
64+
65+
# Save report
66+
repo_name = Path(repo_path.rstrip("/")).name
67+
report_file = f"security-report-{repo_name}.md"
68+
Path(report_file).write_text(report)
69+
70+
# Print summary
71+
stats = pipeline.stats
72+
print()
73+
print("=" * 70)
74+
print(" SCAN COMPLETE")
75+
print("=" * 70)
76+
print()
77+
print(f" Duration: {int(elapsed // 60)}m {int(elapsed % 60)}s")
78+
print(f" Findings: {stats['unique']} unique ({stats['duplicates']} duplicates filtered)")
79+
print(f" Critical: {stats['by_severity'].get('critical', 0)}")
80+
print(f" High: {stats['by_severity'].get('high', 0)}")
81+
print(f" Medium: {stats['by_severity'].get('medium', 0)}")
82+
print(f" Low: {stats['by_severity'].get('low', 0)}")
83+
print(f" Info: {stats['by_severity'].get('info', 0)}")
84+
print()
85+
print(f" Report saved to: {report_file}")
86+
print()
87+
88+
# Print agent stats
89+
for name, agent in pipeline.agents.items():
90+
s = agent.get_stats()
91+
print(f" [{name}] model={s['model']} tokens={s['total_tokens']:,} "
92+
f"tasks={s['tasks_executed']} success={s['success_rate']:.0%}")
93+
94+
print()
95+
96+
97+
if __name__ == "__main__":
98+
if len(sys.argv) < 2:
99+
print("Usage: python examples/security_firm_demo.py <repo_path_or_url>")
100+
print()
101+
print("Examples:")
102+
print(" python examples/security_firm_demo.py /tmp/my-project")
103+
print(" python examples/security_firm_demo.py https://github.com/org/repo")
104+
sys.exit(1)
105+
106+
main(sys.argv[1])

src/firm/security_firm/__init__.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
"""FIRM Security Firm — Multi-agent repository security scanner.
2+
3+
Orchestrates 4 specialised LLM agents through FIRM Protocol to scan
4+
Git repositories for vulnerabilities, misconfigurations, and secrets.
5+
6+
Agents:
7+
- security-director (claude-opus-4.6) — orchestrates + triages
8+
- code-scanner (gpt-5.4) — code review
9+
- static-analyzer (gpt-5.3-codex) — semgrep + deps + secrets
10+
- report-synthesizer (gemini-3.1-pro) — final report
11+
12+
All agents run via copilot-pro (zero API cost), with 1M tokens each.
13+
14+
Usage::
15+
16+
from firm.security_firm import create_security_firm
17+
18+
ctx = create_security_firm("/path/to/repo")
19+
report = ctx["pipeline"].run()
20+
print(report)
21+
"""
22+
23+
__version__ = "0.1.0"
24+
25+
from firm.security_firm.agents import SECURITY_AGENTS, AgentSpec, get_role_def
26+
from firm.security_firm.factory import create_security_firm
27+
from firm.security_firm.findings import (
28+
Finding,
29+
FindingsDB,
30+
FindingStatus,
31+
Severity,
32+
)
33+
from firm.security_firm.pipeline import SecurityPipeline
34+
from firm.security_firm.report import ReportGenerator
35+
from firm.security_firm.tools.repo_scanner import make_repo_tools
36+
37+
__all__ = [
38+
# Factory
39+
"create_security_firm",
40+
# Pipeline
41+
"SecurityPipeline",
42+
# Agents
43+
"SECURITY_AGENTS",
44+
"AgentSpec",
45+
"get_role_def",
46+
# Findings
47+
"Finding",
48+
"FindingsDB",
49+
"FindingStatus",
50+
"Severity",
51+
# Report
52+
"ReportGenerator",
53+
# Tools
54+
"make_repo_tools",
55+
]

0 commit comments

Comments
 (0)