openenv-secaudit / server /observation.py
dexter-2k's picture
Upload folder using huggingface_hub
ee929ba verified
Raw
History Blame Contribute Delete
4.72 kB
"""Ranked action suggestions and observation helpers for SecretsAuditEnv."""
from __future__ import annotations
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
pass
# Files that are high-risk for containing secrets
_HIGH_RISK_KEYWORDS = [
".env", "config", "secret", "deploy", "billing", "auth",
"setup", "credential", "token", "key", "password", "passwd",
"private", "cert", "vault",
]
def estimate_file_suspicion(path: str) -> float:
"""Heuristic leak-probability score for a file path (0.0–0.95)."""
score = 0.3
lower = path.lower()
for keyword in _HIGH_RISK_KEYWORDS:
if keyword in lower:
score += 0.12
return round(min(score, 0.95), 2)
def compute_ranked_actions(
inspected_files: set[str],
deep_inspected: set[str],
fixed_secrets: set[str],
visible_secrets: list[dict[str, Any]],
known_files: list[str],
difficulty: str,
hidden_count: int,
) -> list[dict[str, Any]]:
"""Return top-5 ranked action suggestions based on current environment state."""
candidates: list[dict[str, Any]] = []
# Heuristic 1: visible, unfixed secrets β€” highest priority
for secret in visible_secrets:
if secret["id"] not in fixed_secrets:
candidates.append({
"action": "redact_secret",
"args": {"secret_id": secret["id"], "path": secret["path"], "line": secret["line"]},
"reason": (
f"Visible {secret['type']} at {secret['path']}:{secret['line']} "
f"not yet remediated"
),
"priority": 0.92,
})
# Heuristic 2: uninspected high-risk files
for path in known_files:
if path not in inspected_files:
score = estimate_file_suspicion(path)
candidates.append({
"action": "inspect_file",
"args": {"path": path},
"reason": f"Uninspected file with {score:.0%} leak probability",
"priority": score,
})
# Heuristic 3: git history scan for medium/hard if not yet done
if difficulty in ("medium", "hard") and not deep_inspected:
candidates.append({
"action": "inspect_git_history",
"args": {"path": "."},
"reason": (
"Git history not yet scanned β€” likely contains "
"removed-but-committed secrets"
),
"priority": 0.75,
})
# Heuristic 4: hidden secrets hint β€” suggest encoded inspection
if hidden_count > 0 and not deep_inspected:
candidates.append({
"action": "inspect_encoded",
"args": {"path": ".", "line": 0},
"reason": (
f"{hidden_count} hidden secret(s) remain β€” "
f"inspect encoded blobs or git history"
),
"priority": 0.68,
})
# Heuristic 5: all visible secrets fixed β†’ run gitleaks validation
all_visible_fixed = all(s["id"] in fixed_secrets for s in visible_secrets)
if all_visible_fixed and visible_secrets:
candidates.append({
"action": "run_gitleaks",
"args": {},
"reason": (
"All visible secrets remediated β€” "
"run gitleaks to check for residuals"
),
"priority": 0.85,
})
# Sort descending by priority, deduplicate by action+path, return top 5
candidates.sort(key=lambda x: x["priority"], reverse=True)
seen: set[str] = set()
unique: list[dict[str, Any]] = []
for c in candidates:
key = f"{c['action']}:{c['args'].get('path', '')}"
if key not in seen:
seen.add(key)
unique.append(c)
if len(unique) >= 5:
break
return unique
def get_top_blocker(
visible_secrets: list[dict[str, Any]],
fixed_secrets: set[str],
hidden_count: int,
difficulty: str,
) -> str:
"""Return a single-sentence description of the highest-priority next action."""
for secret in visible_secrets:
if secret["id"] not in fixed_secrets:
return (
f"Fix visible {secret['type']} on "
f"{secret['path']}:{secret['line']} first."
)
if hidden_count > 0:
if difficulty in ("medium", "hard"):
return (
f"{hidden_count} hidden secret(s) remain β€” "
f"run inspect_git_history or inspect_encoded to surface them."
)
return f"{hidden_count} hidden secret(s) remain β€” run inspect_file on suspicious paths."
return "All known secrets addressed β€” submit for final grading."