From d47d039331f63e45a916671ef0039a719217b376 Mon Sep 17 00:00:00 2001 From: Oliver Braasch Date: Wed, 23 Sep 2026 22:30:42 +0200 Subject: [PATCH] Dateien nach "/" hochladen --- app.py | 57 +++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/app.py b/app.py index 9e20db4..1155e94 100644 --- a/app.py +++ b/app.py @@ -25,6 +25,7 @@ import tempfile import threading import time import urllib.request +import zipfile from datetime import datetime from functools import wraps from pathlib import Path @@ -208,10 +209,43 @@ def normalize_components(raw_components: list) -> list: return normalized +# --------------------------------------------------------------------------- # +# Anfang der eigentlichen Skill-Datei (Name/Beschreibung/Einleitung) holen – +# getrennt von SkillSpectors eigenem Scan, nur um der KI echten Kontext für +# den "Wofür ist das?"-Absatz zu geben statt nur der Sicherheitsfunde. +# --------------------------------------------------------------------------- # +def extract_skill_context(target: str, is_zip: bool, work_dir: str) -> str: + context_dir = Path(work_dir) / "context_extract" + try: + context_dir.mkdir(exist_ok=True) + if is_zip: + with zipfile.ZipFile(target) as zf: + zf.extractall(context_dir) + else: + subprocess.run( + ["git", "clone", "--depth", "1", target, str(context_dir / "repo")], + timeout=60, + capture_output=True, + text=True, + ) + candidates = ( + list(context_dir.rglob("SKILL.md")) + or list(context_dir.rglob("skill.md")) + or list(context_dir.rglob("README.md")) + ) + if not candidates: + return "" + return candidates[0].read_text(errors="ignore")[:3000] + except Exception: + return "" + finally: + shutil.rmtree(context_dir, ignore_errors=True) + + # --------------------------------------------------------------------------- # # Deutsche Klartext-Zusammenfassung des Reports per LLM (OpenRouter-kompatibel) # --------------------------------------------------------------------------- # -def generate_report_summary(result: dict) -> str | None: +def generate_report_summary(result: dict, skill_context: str = "") -> str | None: if not OPENAI_API_KEY: return None @@ -243,16 +277,20 @@ def generate_report_summary(result: dict) -> str | None: prompt = ( "Du bekommst das JSON-Ergebnis eines automatisierten Sicherheits-Scans für einen " - "AI-Agent-Skill. Schreibe auf Deutsch einen kurzen, laienverständlichen Bericht für " - "jemanden ohne Security-Hintergrund, als Fließtext in 4 kurzen Absätzen, getrennt " - "durch eine Leerzeile (keine Überschriften, keine Code-Blöcke, keine Aufzählungszeichen):\n" - "Absatz 1: Wofür dieser Skill laut den vorliegenden Daten (Dateinamen, Metadaten, " - "Fundtexte) gedacht ist – 1-2 Sätze. Falls der Zweck nicht erkennbar ist, schreibe " - "das ehrlich so.\n" + "AI-Agent-Skill, sowie (falls vorhanden) den Anfang der eigentlichen Skill-Datei. " + "Schreibe auf Deutsch einen kurzen, laienverständlichen Bericht für jemanden ohne " + "Security-Hintergrund, als Fließtext in 4 kurzen Absätzen, getrennt durch eine " + "Leerzeile (keine Überschriften, keine Code-Blöcke, keine Aufzählungszeichen):\n" + "Absatz 1: Wofür dieser Skill gedacht ist – nutze dafür in erster Linie den Auszug " + "aus der Skill-Datei (Name/Beschreibung/Einleitung), 1-2 Sätze. Nur falls kein " + "Auszug vorliegt oder daraus kein Zweck erkennbar ist, stütze dich ersatzweise auf " + "Dateinamen und Fundtexte aus dem Scan-Ergebnis; ist auch daraus nichts erkennbar, " + "schreibe das ehrlich so.\n" "Absatz 2: Gesamteinschätzung des Risikos in 1-2 Sätzen.\n" "Absatz 3: Die wichtigsten Funde in einfachen Worten, ohne unerklärte Fachbegriffe.\n" "Absatz 4: Konkrete Handlungsempfehlung (bedenkenlos nutzbar / mit Vorsicht " "nutzbar / besser nicht installieren) und eine kurze Begründung warum.\n\n" + f"Auszug aus der Skill-Datei:\n{skill_context or '(kein Auszug verfügbar)'}\n\n" f"Scan-Ergebnis:\n{json.dumps(compact, ensure_ascii=False)}" ) @@ -561,7 +599,10 @@ def index(): summary_text = None summary_failed = False if use_llm: - summary_text = generate_report_summary(result) + skill_context = extract_skill_context( + target, is_zip=bool(zip_file and zip_file.filename), work_dir=work_dir + ) + summary_text = generate_report_summary(result, skill_context) summary_failed = summary_text is None target_label = git_url if git_url else (zip_file.filename if zip_file else "-")