Dateien nach "/" hochladen

This commit is contained in:
Oliver Braasch committed 2026-09-23 22:30:42 +02:00
1 parent 387779a4ef
commit d47d039331
1 file changed
+49 -8
+49 -8
View File
@@ -25,6 +25,7 @@ import tempfile
import threading import threading
import time import time
import urllib.request import urllib.request
import zipfile
from datetime import datetime from datetime import datetime
from functools import wraps from functools import wraps
from pathlib import Path from pathlib import Path
@@ -208,10 +209,43 @@ def normalize_components(raw_components: list) -> list:
return normalized 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) # 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: if not OPENAI_API_KEY:
return None return None
@@ -243,16 +277,20 @@ def generate_report_summary(result: dict) -> str | None:
prompt = ( prompt = (
"Du bekommst das JSON-Ergebnis eines automatisierten Sicherheits-Scans für einen " "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 " "AI-Agent-Skill, sowie (falls vorhanden) den Anfang der eigentlichen Skill-Datei. "
"jemanden ohne Security-Hintergrund, als Fließtext in 4 kurzen Absätzen, getrennt " "Schreibe auf Deutsch einen kurzen, laienverständlichen Bericht für jemanden ohne "
"durch eine Leerzeile (keine Überschriften, keine Code-Blöcke, keine Aufzählungszeichen):\n" "Security-Hintergrund, als Fließtext in 4 kurzen Absätzen, getrennt durch eine "
"Absatz 1: Wofür dieser Skill laut den vorliegenden Daten (Dateinamen, Metadaten, " "Leerzeile (keine Überschriften, keine Code-Blöcke, keine Aufzählungszeichen):\n"
"Fundtexte) gedacht ist – 1-2 Sätze. Falls der Zweck nicht erkennbar ist, schreibe " "Absatz 1: Wofür dieser Skill gedacht ist – nutze dafür in erster Linie den Auszug "
"das ehrlich so.\n" "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 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 3: Die wichtigsten Funde in einfachen Worten, ohne unerklärte Fachbegriffe.\n"
"Absatz 4: Konkrete Handlungsempfehlung (bedenkenlos nutzbar / mit Vorsicht " "Absatz 4: Konkrete Handlungsempfehlung (bedenkenlos nutzbar / mit Vorsicht "
"nutzbar / besser nicht installieren) und eine kurze Begründung warum.\n\n" "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)}" f"Scan-Ergebnis:\n{json.dumps(compact, ensure_ascii=False)}"
) )
@@ -561,7 +599,10 @@ def index():
summary_text = None summary_text = None
summary_failed = False summary_failed = False
if use_llm: 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 summary_failed = summary_text is None
target_label = git_url if git_url else (zip_file.filename if zip_file else "-") target_label = git_url if git_url else (zip_file.filename if zip_file else "-")