Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions anchor/runtime/decision_auditor.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,8 @@ def audit(self, provider: str, prompt: str, response: str, findings: list, juris
rule_ids = sorted([f.get("rule_id") for f in all_violations if f.get("rule_id")])

# Salt the findings commitment to prevent offline dictionary enumeration
secret_key = os.environ.get("ANCHOR_MAT", os.environ.get("ANCHOR_SECRET_KEY", "default-key")).strip()
secret_key = os.environ.get("ANCHOR_MAT", os.environ.get("ANCHOR_SECRET_KEY", "")).strip()
is_sealed = bool(secret_key)
findings_hash = hmac.new(
secret_key.encode("utf-8"),
(json.dumps(rule_ids) + entry_id).encode("utf-8"),
Expand Down Expand Up @@ -297,7 +298,8 @@ def audit(self, provider: str, prompt: str, response: str, findings: list, juris
"latency_ms": latency_ms,
"prompt_preview": prompt[:200] + "..." if len(prompt) > 200 else prompt,
"response_preview": str(response)[:200] + "..." if len(str(response)) > 200 else str(response)
}
},
is_sealed=is_sealed
)

local_entry_dict = entry.to_dict()
Expand Down
4 changes: 3 additions & 1 deletion anchor/runtime/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class AuditEntry:
prev_chain_hash: str = "" # Hash of previous entry (chain integrity)
chain_hash: str = ""
signature: str = ""
is_sealed: bool = True

# Raw Data (Local Only)
violations: List[Dict[str, Any]] = field(default_factory=list)
Expand Down Expand Up @@ -68,7 +69,8 @@ def to_dict(self) -> Dict[str, Any]:
"findings_hash": self.findings_hash,
"prev_chain_hash": self.prev_chain_hash,
"chain_hash": self.chain_hash,
"signature": self.signature
"signature": self.signature,
"is_sealed": self.is_sealed
},
"telemetry": self.telemetry
}
Expand Down
6 changes: 5 additions & 1 deletion anchor/runtime/relay_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,11 @@ async def handler(websocket):
msg = json.loads(raw_msg)
m_type = msg.get("type")
if m_type == "AUDIT_HEADER":
self.received_headers.append(msg.get("payload"))
payload = msg.get("payload") or {}
if "status" not in payload:
is_compliant = payload.get("is_compliant", True)
payload["status"] = "CLEAN" if is_compliant else "VIOLATION"
self.received_headers.append(payload)
elif m_type == "FORENSIC_RESPONSE" or m_type == "pull_response":
payload = msg.get("payload") or msg
entry_id = payload.get("entry_id")
Expand Down
24 changes: 24 additions & 0 deletions tests/unit/test_feedback_fixes.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,27 @@ def test_static_detectors_mitigations():
assert rx_010.search("eval(user_code)") is not None
assert rx_010.search("pickle.loads(payload)") is not None
assert rx_010.search("other_func()") is None

def test_is_sealed_field():
auditor = DecisionAuditor()
auditor.get_last_runtime_hash = MagicMock(return_value="0".zfill(64))

# 1. No secret configured -> is_sealed should be False
with patch.dict('os.environ', {}, clear=True):
entry_unsealed = auditor.audit(
provider="test-provider",
prompt="test prompt",
response="test response",
findings=[]
)
assert entry_unsealed["cryptography"]["is_sealed"] is False

# 2. Secret configured -> is_sealed should be True
with patch.dict('os.environ', {"ANCHOR_SECRET_KEY": "some-secret"}):
entry_sealed = auditor.audit(
provider="test-provider",
prompt="test prompt",
response="test response",
findings=[]
)
assert entry_sealed["cryptography"]["is_sealed"] is True
Loading