Contribuer¶
Environnement de développement¶
Il faut Python 3.14, uv et Node.js 24 (le devcontainer les fournit et installe les dépendances à sa création) :
git clone https://github.com/cyr-ius/security-review.git
cd security-review
uv sync --extra dev --extra docs
npm --prefix web ci # Angular, Prettier (Node.js 24)
npm --prefix web run build # interface servie par le contrôleur sur /ui/
uv run security-review-controller db upgrade
Sans la build Angular, le contrôleur ne sert que l'API REST (/api/v1). prek install
(facultatif), linters, formateurs et revues de sécurité : voir
Vérifications, revues et publication.
Dans VS Code (.vscode/) :
Configuration de launch.json |
Rôle |
|---|---|
| MCP server + controller | Lance la tâche Database upgrade, puis les deux processus sur la même base |
| MCP server (HTTP, port 8000) | Serveur MCP seul ; la base doit déjà être migrée |
| Controller (web UI and API, port 8080) | Contrôleur seul ; migre la base et affiche le mot de passe du compte admin initial au premier démarrage |
| Controller CLI (prompt for arguments) | Une commande du contrôleur (db status, token list…) sous le débogueur |
| Controller + web UI (Angular, port 4200) | Contrôleur et application Angular sous le débogueur, rechargement à chaud |
| Web UI + API (Angular dev server, port 4200) | Lance la tâche Web UI + API: dev servers (contrôleur sur 8080 et ng serve), attend qu'ils soient prêts, puis ouvre Chrome sur http://localhost:4200/ui/ avec les points d'arrêt TypeScript |
| Pytest (current file) | Tests du fichier ouvert |
Tâche de tasks.json |
Commande |
|---|---|
| Build security_review_mcp | uv sync --extra dev --extra docs --extra postgres |
| Database upgrade | uv run security-review-controller db upgrade (après Build) |
| Tests / Lint | pytest, puis ruff et mkdocs build --strict |
| Web UI: build / Web UI: dev server (port 4200) | Build Angular servie par le contrôleur, ou ng serve avec /api redirigé vers le port 8080 |
| API: controller (port 8080) / Web UI + API: dev servers | Contrôleur seul hors débogueur (security-review-controller serve), ou contrôleur et ng serve en parallèle |
| Docs: serve (port 8001) | mkdocs serve |
| Docker: compose up / down | Pile docker-compose.yml de l'image, avec sa propre base PostgreSQL (mêmes ports 8000 et 8080 : arrêtez les configurations de debug avant) |
Devcontainer¶
Le dépôt fournit un devcontainer (.devcontainer/) avec Python, uv, Node.js, un démon Docker
dédié (feature docker-in-docker) et une base PostgreSQL 18. compose.yaml décrit deux
services : app, le conteneur de développement, et db, la base, joignable depuis app sous
le nom db et conservée dans le volume secreview-dev-pg entre deux reconstructions.
SECREVIEW_DATABASE_URL y pointe par défaut : le serveur MCP, le contrôleur et la CLI utilisent
PostgreSQL. Les tests, eux, utilisent toujours une base SQLite en mémoire et ignorent votre
fichier .env et les variables SECREVIEW_* du shell.
À sa création, le devcontainer installe le client psql, les hooks prek et l'environnement
complet (uv sync --extra dev --extra docs --extra postgres, npm --prefix web ci), puis migre la base. Il redirige les
ports 8000 (serveur MCP), 8080 (contrôleur), 4200 (serveur de dev Angular), 8001 (doc) et 5432
(PostgreSQL, identifiants de développement secreview / secreview).
psql -h db -U secreview secreview # mot de passe : secreview
SECREVIEW_DATABASE_URL=sqlite:///./dev.db security-review-mcp serve # revenir ponctuellement à SQLite
Le démon Docker permet de construire et de lancer l'image du Dockerfile sans quitter le conteneur.
Construire l'image¶
docker build -t security-review-mcp . # SQLite et PostgreSQL (pilote inclus)
Le build compile aussi l'interface web (étape Node.js) ;
elle est servie sur /ui/ par le contrôleur.
L'image tourne sous un utilisateur non root (uid 10001), sans sources ni outils de build. Son
HEALTHCHECK (python -m security_review_mcp.healthcheck, toutes les 30 secondes) interroge
/healthz du serveur MCP HTTP ou du contrôleur sur l'interface de bouclage, en HTTPS quand le
TLS est activé (en ne faisant confiance qu'au certificat du conteneur) ; en stdio, rien n'écoute
et le conteneur reste sain, et avec le TLS mutuel (SECREVIEW_TLS_CLIENT_CA) il n'interroge
rien : appuyez-vous sur les sondes de l'orchestrateur. La
base SQLite est dans le volume /var/lib/secreview. Le fichier .env n'est pas copié dans l'image :
passez la configuration avec -e ou --env-file.
Définition de « terminé »¶
Une contribution, humaine ou produite par un agent IA, n'est terminée que si le comportement
qu'elle ajoute ou corrige est vérifié par un test pertinent, nouveau ou existant, que la documentation docs/ est à jour dans les deux langues et que les README.md, qui
restent des résumés, le sont aussi. Quand le serveur MCP security-review est opérationnel, les changements sont en outre
relus avec lui (le projet se relit lui-même) et le rapport est enregistré. Les règles détaillées
(conventions, invariants de sécurité, correspondance code → pages de doc) sont dans AGENTS.md
à la racine du dépôt ; CLAUDE.md et .github/copilot-instructions.md y renvoient.
La méthode de test est dans Tests ; les vérifications à lancer et la procédure de revue sont dans Vérifications, revues et publication.
Structure du code¶
src/security_review_mcp/
├── server.py # prompts, outils, ressources, point d'entrée du serveur MCP
├── prompts.py # construction des prompts
├── standards.py # normes de développement : stockage, recherche par technologie / fichier, rendu
├── controller.py # point d'entrée du contrôleur (serve, db et commandes d'administration)
├── ci_client.py # `security-review-ci` : client de pipeline du contrôleur, liste des fichiers (bibliothèque standard uniquement)
├── cli.py # commandes du contrôleur : db, advisories, rules, token, user, group, project, audit
├── http_server.py # HTTP des deux processus : jetons Bearer et rôles, TLS, /healthz, uvicorn
├── healthcheck.py # HEALTHCHECK de l'image Docker (/healthz des processus HTTP)
├── config.py # paramètres (SECREVIEW_*)
├── app_settings.py # réglages modifiables dans l'interface (langue, proxy sortant, OIDC), en base
├── proxy.py # proxy sortant du contrôleur (OSV, OIDC) : URL, no_proxy, handler urllib
├── update_check.py # recherche d'une nouvelle version sur GitHub (page À propos, facultatif)
├── storage/ # persistance
│ ├── database.py # moteur, sessions et migrations (Alembic)
│ ├── models.py # modèles SQLModel (tables + schémas)
│ ├── migrations/ # environnement Alembic et révisions du schéma (versions/)
│ ├── retention.py # purge quotidienne des rapports sans findings et des anciens événements d'audit
│ └── project_names.py # normalisation des noms de projet (toute entrée)
├── reports/ # rapports de sécurité
│ ├── services.py # logique de persistance des rapports
│ ├── coverage.py # contrôle les résultats de checklist et règles déclarés avec un rapport
│ ├── sarif.py # export SARIF 2.1.0
│ └── trends.py # rapport de tendance
├── rules/ # règles de scan et checklists
│ ├── scanner.py # moteur de scan, suppression inline, masquage des secrets
│ ├── syntax_analysis.py # analyses structurelles Tree-sitter, séparées des règles ligne par ligne
│ ├── codescan.py # scan du code complet des fichiers envoyés par security-review-ci (findings)
│ ├── default_rules.toml # règles et checklists par défaut, copiées en base au premier lancement
│ ├── rules_loader.py # validation des règles, lecture des packs TOML et du fichier par défaut
│ ├── rule_store.py # règles en base : amorçage, import/export, activation, suppression
│ ├── registry.py # règles/checklists actives (lues en base), rechargement
│ └── checklists.py # structure d'un item de checklist
├── deps/ # analyse des dépendances
│ ├── dependencies.py # analyseurs de manifestes / lockfiles, hygiène
│ ├── depscan.py # scan de dépendances et conversion en findings
│ ├── advisories.py # import OSV, correspondance des versions
│ ├── advisory_sync.py # téléchargement OSV par le contrôleur (proxy, mise à jour quotidienne, historique)
│ └── versions.py # comparaison de versions
├── auth/ # identité et accès
│ ├── access_control.py # permissions, rôles, groupes et membres des comptes web, enrôlement des projets
│ ├── token_store.py # jetons Bearer en base : création, expiration, renouvellement, révocation
│ ├── web_users.py # comptes de l'interface web, locaux (scrypt) ou OIDC (création à la volée), sessions, admin initial
│ ├── oidc.py # connexion OIDC OpenID Connect à l'interface web (contrôleur)
│ ├── rate_limit.py # limites de débit de l'API REST et des connexions (fenêtre glissante en base)
│ └── enrollment_api.py # endpoint public POST /api/v1/enroll du serveur MCP
├── observability/ # journal d'audit et métriques
│ ├── audit.py # journal d'audit : événements des décisions de triage, propositions, jetons et enrôlements
│ ├── audit_syslog.py # envoi des événements d'audit vers syslog par le contrôleur (facultatif)
│ └── metrics.py # métriques Prometheus du contrôleur (/metrics)
├── clients/ # clients CLI qui contactent l'URL donnée par l'opérateur
│ ├── commands.py # commande `enroll` de security-review-mcp
│ └── enrollment.py # client de `enroll` : enrôlement d'un projet sur un serveur en mode partagé
├── connectors/ # findings envoyés vers des systèmes externes : api (API des connecteurs),
│ # registry, connections, transport (client HTTP), core (envoi), jira, servicenow
└── web_api/ # contrôleur : API REST /api/v1 et fichiers de l'application (/ui)
├── __init__.py # create_app, fichiers statiques de /ui, assemblage des routeurs
├── schemas.py # modèles de requête et de réponse de chaque route
├── deps.py # identité de l'appelant, permissions, portée projet
└── *_routes.py # un routeur par domaine (auth, account, report, ci, rule, token, admin, access)
tests/ # pytest (scanner, services, client MCP de bout en bout)
web/ # application Angular (compilée dans src/security_review_mcp/webui/)
Le serveur MCP n'importe jamais les modules du contrôleur qui ouvrent des connexions sortantes
ou servent ses routes (controller, deps/advisory_sync, auth/oidc,
observability/audit_syslog, connectors, update_check, web_api), même indirectement :
tests/test_server.py le vérifie. Un module partagé par les deux processus (comme
app_settings) les importe dans la fonction qui en a besoin, jamais en tête.
Développement par composant¶
Chaque partie du projet a sa page, avec ses conventions, ses invariants et la façon de la tester :
| Page | Code | Contenu |
|---|---|---|
| Serveur MCP | server.py, prompts.py, rules/ |
Outils, prompts et ressources, règles de scan, invariants de sécurité du processus MCP |
| Contrôleur (FastAPI) | web_api/, cli.py, storage/ |
Routes REST et leurs schémas, permissions, paramètres, CLI, migrations du schéma |
| Interface web (Angular) | web/ |
Build et serveur de développement, conventions de code, traductions |
| Écrire un connecteur | connectors/api.py, examples/connector/ |
Connecteur tiers : classe Connector, point d'entrée, garanties du contrôleur |
| Documentation | docs/, mkdocs.yml, README.md |
Rédaction et construction de la documentation bilingue, README, publication |
| Tests | tests/, tests/conftest.py |
Quoi tester, conventions, fixtures, tests par type de code |
| Vérifications, revues et publication | .pre-commit-config.yaml, .github/workflows/ |
Linters, formateurs, tests, revue de sécurité, branches, versions |
Les normes génériques de chaque technologie (Python et FastAPI, Angular, tests) sont servies par
le projet lui-même : prompt development-standards, outil get_development_standards (voir
normes de développement). Ces pages ne gardent que ce qui est propre à
ce dépôt ; en cas de conflit, elles prévalent.