rhodawk-ai-devops-engine / chain_analyzer.py
Architect8999's picture
feat: ethical AVR pipeline — semantic extractor, harness factory, chain analyzer, disclosure vault, Security Research tab
9452af2 verified
Raw
History Blame Contribute Delete
9.59 kB
"""
Rhodawk AI — Vulnerability Chain Analyzer
==========================================
Documents how primitive findings (individual assumption gaps + PoC results)
might combine into higher-severity chains.
ETHICAL CONSTRAINTS:
- Chains are THEORETICAL proposals documented for human review
- No chain is automatically executed
- All chain proposals are stored with status PENDING_HUMAN_REVIEW
- Human operator must approve or reject every chain before any further action
Orchestrated by Nous Hermes 3 via OpenRouter.
"""
from __future__ import annotations
import hashlib
import json
import os
import re
import sqlite3
import time
from typing import Optional
import requests
OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY", "")
HERMES_MODEL = os.getenv(
"RHODAWK_RESEARCH_MODEL",
"nousresearch/hermes-3-llama-3.1-405b:free",
)
CHAIN_DB = os.getenv("RHODAWK_CHAIN_DB", "/data/chain_memory.sqlite")
def _init_db() -> None:
os.makedirs(os.path.dirname(CHAIN_DB), exist_ok=True)
conn = sqlite3.connect(CHAIN_DB)
conn.executescript("""
CREATE TABLE IF NOT EXISTS primitive_findings (
id TEXT PRIMARY KEY,
repo TEXT NOT NULL,
gap_id TEXT NOT NULL,
severity TEXT,
description TEXT,
triggered INTEGER DEFAULT 0,
confidence TEXT DEFAULT 'UNKNOWN',
created_at REAL,
harness_out TEXT
);
CREATE TABLE IF NOT EXISTS chains (
id TEXT PRIMARY KEY,
repo TEXT NOT NULL,
primitive_ids TEXT NOT NULL,
description TEXT,
chained_severity TEXT,
confidence TEXT,
conditions TEXT,
theoretical_impact TEXT,
human_notes TEXT,
status TEXT DEFAULT 'PENDING_HUMAN_REVIEW',
created_at REAL,
human_approved INTEGER DEFAULT 0,
human_reviewer TEXT,
reviewed_at REAL
);
""")
conn.commit()
conn.close()
def store_primitive(
repo: str,
gap_id: str,
severity: str,
description: str,
triggered: bool,
confidence: str = "UNKNOWN",
harness_result: Optional[dict] = None,
) -> str:
"""Persist a primitive finding from the harness execution."""
_init_db()
finding_id = hashlib.sha256(
f"{repo}:{gap_id}:{time.time()}".encode()
).hexdigest()[:16]
conn = sqlite3.connect(CHAIN_DB)
conn.execute(
"""INSERT OR REPLACE INTO primitive_findings
(id, repo, gap_id, severity, description, triggered, confidence, created_at, harness_out)
VALUES (?,?,?,?,?,?,?,?,?)""",
(
finding_id, repo, gap_id, severity, description,
1 if triggered else 0, confidence, time.time(),
json.dumps(harness_result or {}),
),
)
conn.commit()
conn.close()
return finding_id
def analyze_chains(repo: str) -> list[dict]:
"""
Ask Hermes to propose vulnerability chains from stored primitives.
Returns THEORETICAL proposals — all tagged PENDING_HUMAN_REVIEW.
Nothing is executed automatically.
"""
_init_db()
conn = sqlite3.connect(CHAIN_DB)
rows = conn.execute(
"""SELECT id, gap_id, severity, description, triggered, confidence
FROM primitive_findings WHERE repo = ?
ORDER BY created_at DESC""",
(repo,),
).fetchall()
conn.close()
if len(rows) < 2:
return []
primitives_text = "\n".join(
f"- [{r[0]}] Gap: {r[1]} | Sev: {r[2]} | Triggered: {bool(r[4])} "
f"| Confidence: {r[5]} | {r[3][:120]}"
for r in rows
)
headers = {
"Authorization": f"Bearer {OPENROUTER_API_KEY}",
"Content-Type": "application/json",
"HTTP-Referer": "https://rhodawk.ai",
}
payload = {
"model": HERMES_MODEL,
"messages": [
{
"role": "system",
"content": (
"You are a senior security researcher conducting responsible vulnerability research. "
"Analyse primitive findings and propose THEORETICAL vulnerability chains for human review. "
"Be rigorous and conservative — only propose chains that are logically sound based on "
"the available evidence. Mark any speculation clearly. Output valid JSON only."
),
},
{
"role": "user",
"content": (
f"Analyse these primitive findings from {repo} and identify plausible chains.\n\n"
f"PRIMITIVES:\n{primitives_text}\n\n"
"Output ONLY this JSON:\n"
'{"chains": [{'
'"primitive_ids": ["id1","id2"],'
'"description": "Step-by-step logical chain",'
'"chained_severity": "P1|P2|P3",'
'"confidence": "HIGH|MEDIUM|LOW",'
'"required_conditions": ["condition1"],'
'"theoretical_impact": "What an attacker could theoretically achieve",'
'"human_verification_needed": "What a human researcher must manually verify before treating this as real"'
"}]}"
),
},
],
"max_tokens": 2048,
"temperature": 0.1,
}
try:
resp = requests.post(
"https://openrouter.ai/api/v1/chat/completions",
headers=headers, json=payload, timeout=120,
)
resp.raise_for_status()
raw = resp.json()["choices"][0]["message"]["content"]
match = re.search(r"\{[\s\S]*\}", raw)
if not match:
return []
data = json.loads(match.group())
chains = data.get("chains", [])
conn = sqlite3.connect(CHAIN_DB)
for chain in chains:
chain_id = hashlib.sha256(
f"{repo}:{':'.join(chain.get('primitive_ids', []))}:{time.time()}".encode()
).hexdigest()[:16]
chain["id"] = chain_id
conn.execute(
"""INSERT OR IGNORE INTO chains
(id, repo, primitive_ids, description, chained_severity, confidence,
conditions, theoretical_impact, status, created_at)
VALUES (?,?,?,?,?,?,?,?,'PENDING_HUMAN_REVIEW',?)""",
(
chain_id, repo,
json.dumps(chain.get("primitive_ids", [])),
chain.get("description", ""),
chain.get("chained_severity", "P3"),
chain.get("confidence", "LOW"),
json.dumps(chain.get("required_conditions", [])),
chain.get("theoretical_impact", ""),
time.time(),
),
)
conn.commit()
conn.close()
return chains
except Exception as e:
return [{"error": str(e)}]
def get_pending_chains(repo: Optional[str] = None) -> list[dict]:
_init_db()
conn = sqlite3.connect(CHAIN_DB)
if repo:
rows = conn.execute(
"""SELECT id, repo, description, chained_severity, confidence, status, created_at
FROM chains WHERE repo=? AND status='PENDING_HUMAN_REVIEW'
ORDER BY created_at DESC""",
(repo,),
).fetchall()
else:
rows = conn.execute(
"""SELECT id, repo, description, chained_severity, confidence, status, created_at
FROM chains WHERE status='PENDING_HUMAN_REVIEW'
ORDER BY created_at DESC""",
).fetchall()
conn.close()
return [
{
"id": r[0], "repo": r[1], "description": r[2],
"severity": r[3], "confidence": r[4], "status": r[5], "created_at": r[6],
}
for r in rows
]
def get_all_primitives(repo: Optional[str] = None) -> list[dict]:
_init_db()
conn = sqlite3.connect(CHAIN_DB)
if repo:
rows = conn.execute(
"SELECT id, repo, gap_id, severity, description, triggered, confidence, created_at "
"FROM primitive_findings WHERE repo=? ORDER BY created_at DESC",
(repo,),
).fetchall()
else:
rows = conn.execute(
"SELECT id, repo, gap_id, severity, description, triggered, confidence, created_at "
"FROM primitive_findings ORDER BY created_at DESC",
).fetchall()
conn.close()
return [
{
"id": r[0], "repo": r[1], "gap_id": r[2], "severity": r[3],
"description": r[4], "triggered": bool(r[5]),
"confidence": r[6], "created_at": r[7],
}
for r in rows
]
def approve_chain(chain_id: str, reviewer: str) -> bool:
_init_db()
conn = sqlite3.connect(CHAIN_DB)
conn.execute(
"UPDATE chains SET status='HUMAN_APPROVED', human_approved=1, "
"human_reviewer=?, reviewed_at=? WHERE id=?",
(reviewer, time.time(), chain_id),
)
conn.commit()
conn.close()
return True
def reject_chain(chain_id: str, reviewer: str) -> bool:
_init_db()
conn = sqlite3.connect(CHAIN_DB)
conn.execute(
"UPDATE chains SET status='HUMAN_REJECTED', human_reviewer=?, reviewed_at=? WHERE id=?",
(reviewer, time.time(), chain_id),
)
conn.commit()
conn.close()
return True