Etape 3 + refonte visuelle + corrections etape 2

This commit is contained in:
Chevallier
2026-07-07 09:57:21 +02:00
parent 17e887b268
commit 7b1a975f06
48 changed files with 6551 additions and 59 deletions

View File

@@ -0,0 +1,20 @@
FROM semgrep/semgrep:latest
USER root
RUN sed -i 's/https/http/g' /etc/apk/repositories && \
apk update && apk add --no-cache python3 py3-pip
RUN pip install --no-cache-dir \
--trusted-host pypi.org \
--trusted-host files.pythonhosted.org \
--break-system-packages \
fastapi uvicorn
WORKDIR /app
COPY main.py .
EXPOSE 8004
CMD ["python3", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8004"]

View File

@@ -1,8 +0,0 @@
async def run_in_sandbox(code: str) -> dict:
"""
Stub minimal pour future exécution sécurisée dans Docker.
"""
return {
"status": "not_implemented",
"logs": ["Sandbox Docker non branchée à l'étape 0."],
}

View File

@@ -0,0 +1,52 @@
import subprocess
import json
import time
from fastapi import FastAPI
app = FastAPI()
@app.post("/scan/{repo_name}")
async def scan_repository(repo_name: str):
repo_path = f"/src/{repo_name}"
issues_list = []
start_time = time.time()
result = subprocess.run(
["semgrep", "scan", "--config=p/r2c-security-audit", "--json", "--quiet", repo_path],
capture_output=True,
text=True
)
duration = round(time.time() - start_time, 2)
try:
if result.stdout.strip():
scan_data = json.loads(result.stdout)
for item in scan_data.get("results", []):
issues_list.append({
"tool": "Semgrep",
"file": item.get("path", "").replace(f"{repo_path}/", ""),
"line": item.get("start", {}).get("line"),
"code": item.get("check_id"),
"severity": item.get("extra", {}).get("severity", "MEDIUM").upper(),
"message": item.get("extra", {}).get("message", "")
})
is_executable = True
stderr_output = result.stderr
except Exception as e:
is_executable = False
stderr_output = f"Erreur parsing JSON Semgrep: {str(e)}\n{result.stderr}"
return {
"results": {
"is_executable": is_executable,
"runtime": {
"exit_code": 0, # <-- ON FORCE À 0 ICI : Tout s'est bien passé pour le scanner
"stdout": "Scan statique universel effectué avec succès.",
"stderr": stderr_output,
"duration_seconds": duration,
"timeout_triggered": False
},
"issues": issues_list
}
}

View File

@@ -0,0 +1,50 @@
import logging
import httpx
from app.core.config import settings
from app.schemas.qa_report import QARawResults, RuntimeOutput
logger = logging.getLogger(__name__)
async_client = httpx.AsyncClient(verify=False)
async def run_project_qa(repo_name: str) -> QARawResults:
"""
Sollicite l'API du conteneur persistant arc-sandbox pour effectuer
une analyse de qualité et sécurité statique (Semgrep).
"""
sandbox_url = f"http://arc-sandbox:8004/scan/{repo_name}"
logger.info(f"[QA Client] Envoi de la requête de scan à la sandbox : {sandbox_url}")
try:
response = await async_client.post(sandbox_url, timeout=120.0)
if response.status_code == 200:
data = response.json()
return QARawResults.model_validate(data.get("results"))
else:
logger.error(f"[QA Client] Erreur de la Sandbox (Status {response.status_code}): {response.text}")
return QARawResults(
is_executable=False,
runtime=RuntimeOutput(
exit_code=response.status_code,
stdout="",
stderr=f"Erreur HTTP Sandbox: {response.text}",
duration_seconds=0,
timeout_triggered=False
),
issues=[]
)
except Exception as e:
logger.error(f"[QA Client] Impossible de joindre l'API de la Sandbox : {str(e)}")
return QARawResults(
is_executable=False,
runtime=RuntimeOutput(
exit_code=-1,
stdout="",
stderr=f"Exception de connexion QA Client: {str(e)}",
duration_seconds=0,
timeout_triggered=False
),
issues=[]
)