mirror of
https://github.com/Rarebuffalo/securelens-backend.git
synced 2026-06-19 07:00:30 +00:00
updated the new feature
This commit is contained in:
@@ -17,9 +17,10 @@ from app.schemas.scan import (
|
||||
ChatResponse,
|
||||
ThreatNarrativeResponse,
|
||||
ScanDiffResponse,
|
||||
ScheduledScanResponse,
|
||||
)
|
||||
|
||||
from app.services.ai import chat_with_scan_context, generate_threat_narrative
|
||||
from app.services.ai import chat_with_scan_context, generate_threat_narrative, generate_diff_narrative
|
||||
|
||||
router = APIRouter(prefix="/scans", tags=["history"])
|
||||
|
||||
@@ -198,7 +199,7 @@ async def diff_scans(
|
||||
):
|
||||
result = await db.execute(
|
||||
select(ScanResult).where(
|
||||
ScanResult.id.in_([old_id, new_id]),
|
||||
ScanResult.id.in_([old_id, new_id]),
|
||||
ScanResult.user_id == current_user.id
|
||||
)
|
||||
)
|
||||
@@ -210,17 +211,28 @@ async def diff_scans(
|
||||
s_old = scans[0] if scans[0].id == old_id else scans[1]
|
||||
s_new = scans[1] if scans[1].id == new_id else scans[0]
|
||||
|
||||
# Convert to set-like structures using issue names
|
||||
# Map issues by name for set-like comparison
|
||||
old_map = {i.get("issue"): i for i in s_old.issues}
|
||||
new_map = {i.get("issue"): i for i in s_new.issues}
|
||||
|
||||
resolved = [v for k, v in old_map.items() if k not in new_map]
|
||||
new_issues = [v for k, v in new_map.items() if k not in old_map]
|
||||
persisting = [v for k, v in new_map.items() if k in old_map]
|
||||
score_change = s_new.security_score - s_old.security_score
|
||||
|
||||
# Ask the AI to narrate the changes in plain English
|
||||
diff_context = {
|
||||
"score_change": score_change,
|
||||
"resolved_issues": resolved,
|
||||
"new_issues": new_issues,
|
||||
"persisting_issues": persisting,
|
||||
}
|
||||
narrative = await generate_diff_narrative(diff_context)
|
||||
|
||||
return ScanDiffResponse(
|
||||
resolved_issues=resolved,
|
||||
new_issues=new_issues,
|
||||
persisting_issues=persisting,
|
||||
score_change=s_new.security_score - s_old.security_score
|
||||
score_change=score_change,
|
||||
narrative=narrative,
|
||||
)
|
||||
|
||||
@@ -23,6 +23,7 @@ from app.services.scanner.ports import PortScanner
|
||||
from app.services.scoring import calculate_layer_statuses, calculate_score
|
||||
from app.services.ai import enhance_security_issues
|
||||
from app.services.threat_intel import get_threat_intel_summary
|
||||
from app.services.webhook_dispatcher import dispatch_webhooks
|
||||
from app.utils.validators import validate_url
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -38,30 +39,6 @@ dns_scanner = DNSScanner()
|
||||
port_scanner = PortScanner()
|
||||
|
||||
|
||||
async def dispatch_webhooks(user_id: str, scan_data: dict, db_session):
|
||||
import hmac, hashlib, json
|
||||
from sqlalchemy import select
|
||||
|
||||
result = await db_session.execute(
|
||||
select(Webhook).where(Webhook.user_id == user_id, Webhook.is_active == True)
|
||||
)
|
||||
hooks = result.scalars().all()
|
||||
if not hooks:
|
||||
return
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
payload = json.dumps(scan_data).encode("utf-8")
|
||||
for hook in hooks:
|
||||
headers = {"Content-Type": "application/json"}
|
||||
if hook.secret_key:
|
||||
sig = hmac.new(hook.secret_key.encode(), payload, hashlib.sha256).hexdigest()
|
||||
headers["X-SecureLens-Signature"] = sig
|
||||
|
||||
try:
|
||||
await client.post(hook.target_url, content=payload, headers=headers, timeout=5.0)
|
||||
except Exception as e:
|
||||
logger.warning(f"Webhook {hook.target_url} failed: {e}")
|
||||
|
||||
|
||||
@router.post("/scan", response_model=ScanResponse)
|
||||
@limiter.limit(settings.rate_limit)
|
||||
|
||||
Reference in New Issue
Block a user