From ef9c5f83e485b5baf938113a630b29af18834b21 Mon Sep 17 00:00:00 2001 From: Ripeeerr Date: Sun, 16 Aug 2026 01:32:30 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D1=80=D0=BE=D1=83=D1=82=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=BE=D1=82=D1=87=D0=B5=D1=82=D0=B0=20=D0=BF=D0=BE=20=20=D1=81?= =?UTF-8?q?=D0=BA=D0=B0=D0=BD=D1=83=20=D0=B2=20JSON?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/routes/scan.py | 69 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/app/routes/scan.py b/app/routes/scan.py index 9763f10..3a6115d 100644 --- a/app/routes/scan.py +++ b/app/routes/scan.py @@ -1,7 +1,11 @@ +from collections import defaultdict + from flask import Blueprint, jsonify from flask_login import current_user, login_required +from sqlalchemy.orm import joinedload -from app.models import Project +from app.models.finding import Finding +from app.models.project import Project from app.models.scan import Scan scan_bp = Blueprint("scan", __name__) @@ -14,7 +18,7 @@ def scan_status(scan_id): Scan.id == scan_id, Project.owner_id == current_user.id ).first() if not scan: - return jsonify({"error": "Нет сканов"}), 404 + return jsonify({"error": "Данного скана не существует"}), 404 return jsonify( { "status": scan.status, @@ -26,3 +30,64 @@ def scan_status(scan_id): "created_at": scan.created_at, } ), 200 + + +@scan_bp.route("/api/scans//report", methods=["GET"]) +@login_required +def report_json(scan_id): + scan = ( + Scan.query.options(joinedload(Scan.project)) + .filter(Scan.id == scan_id, Project.owner_id == current_user.id) + .first() + ) + if not scan: + return jsonify({"error": "Данного скана не существует"}), 404 + if scan.status == "failed": + return jsonify({"error": scan.error_message}), 409 + if scan.status != "done": + return jsonify({"status": scan.status}), 409 + finding = Finding.query.filter( + Scan.id == scan_id, Project.owner_id == current_user.id + ).all() + if scan.status == "done": + findings = [ + { + "id": f.id, + "rule_id": f.rule_id, + "severity": f.severity, + "confidence": f.confidence, + "source": f.source, + "file_path": f.file_path, + "line_no": f.line_no, + "commit_sha": f.commit_sha, + "masked_value": f.masked_value, + "context": f.context, + "status": f.status, + } + for f in finding + ] + + def group_sort_severity(findings): + grouped = defaultdict(list) + for f in findings: + grouped[f["severity"]].append(f) + for finding_list in grouped.values(): + finding_list.sort(key=lambda x: x["file_path"]) + summary = { + severity: len(finding_list) for severity, finding_list in grouped.items() + } + return dict(grouped), summary + + grouped, summary = group_sort_severity(findings) + + return jsonify( + { + "scan_id": scan.id, + "project_id": scan.project.id, + "commit_sha": scan.commit_sha, + "truncated": scan.truncated, + "finished_at": scan.finished_at, + "summary": summary, + "findings": grouped, + } + )