Files
OpenShell/python/openshell/prover/accepted_risks.py
T
Alexander Watson b9fc0d3b8d refactor(prover): simplify to two Zelkova-like verification queries
Narrow OPP to two yes/no security questions:
1. Can data leave this sandbox? (exfiltration)
2. Can the agent write despite read-only intent? (write bypass)

Removes 4 advisory/lint queries (overpermissive methods, L4 gaps,
binary inheritance, inference relay), 3 output modes (Mermaid,
topology, HTML), and fixes 3 bugs (include_workdir not used in
exfil analysis, __all__ broken when protos missing, CLI PYTHONPATH).

~40% line reduction (2900 -> 1769 lines).

Signed-off-by: Alexander Watson <zredlined@gmail.com>
2026-03-31 11:12:44 -07:00

117 lines
3.3 KiB
Python

# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
"""Load and match accepted risk annotations against findings."""
from __future__ import annotations
from dataclasses import dataclass
from typing import TYPE_CHECKING
import yaml
from .queries import Finding
if TYPE_CHECKING:
from pathlib import Path
@dataclass
class AcceptedRisk:
query: str
reason: str
binary: str = ""
endpoint: str = ""
def load_accepted_risks(path: Path) -> list[AcceptedRisk]:
"""Load accepted risks from YAML."""
with open(path) as f: # noqa: PTH123
raw = yaml.safe_load(f)
return [
AcceptedRisk(
query=r.get("query", ""),
reason=r.get("reason", ""),
binary=r.get("binary", ""),
endpoint=r.get("endpoint", ""),
)
for r in (raw.get("accepted_risks") or [])
]
def _path_matches_risk(path, risk: AcceptedRisk) -> bool:
"""Check if a single finding path matches an accepted risk."""
if risk.binary:
path_binary = getattr(path, "binary", "")
if path_binary != risk.binary:
return False
if risk.endpoint:
endpoint_host = getattr(path, "endpoint_host", "")
if endpoint_host != risk.endpoint:
return False
return True
def apply_accepted_risks(
findings: list[Finding],
accepted: list[AcceptedRisk],
) -> list[Finding]:
"""Mark findings as accepted where they match accepted risk annotations.
A finding is accepted if ALL of its paths match at least one accepted risk
entry for that query. If only some paths match, the finding stays active
with the unmatched paths.
"""
if not accepted:
return findings
result = []
for finding in findings:
matching_risks = [r for r in accepted if r.query == finding.query]
if not matching_risks:
result.append(finding)
continue
unmatched_paths = []
matched_reason = ""
for path in finding.paths:
path_accepted = False
for risk in matching_risks:
if _path_matches_risk(path, risk):
path_accepted = True
matched_reason = risk.reason
break
if not path_accepted:
unmatched_paths.append(path)
if not unmatched_paths:
accepted_finding = Finding(
query=finding.query,
title=finding.title,
description=finding.description,
risk=finding.risk,
paths=finding.paths,
remediation=finding.remediation,
accepted=True,
accepted_reason=matched_reason,
)
result.append(accepted_finding)
elif len(unmatched_paths) < len(finding.paths):
result.append(
Finding(
query=finding.query,
title=finding.title,
description=finding.description,
risk=finding.risk,
paths=unmatched_paths,
remediation=finding.remediation,
)
)
else:
result.append(finding)
return result