Dateien nach "/" hochladen
This commit is contained in:
1 parent
387779a4ef
commit
d47d039331
1 file changed
+49
-8
@@ -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 "-")
|
||||||
|
|||||||
Reference in new issue
Block a user