Etape 3 + refonte visuelle + corrections etape 2
This commit is contained in:
20
backend/app/sandbox/Dockerfile.qa
Normal file
20
backend/app/sandbox/Dockerfile.qa
Normal 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"]
|
||||
@@ -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."],
|
||||
}
|
||||
52
backend/app/sandbox/main.py
Normal file
52
backend/app/sandbox/main.py
Normal 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
|
||||
}
|
||||
}
|
||||
50
backend/app/sandbox/qa_client.py
Normal file
50
backend/app/sandbox/qa_client.py
Normal 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=[]
|
||||
)
|
||||
Reference in New Issue
Block a user