Skip to content

Commit 4c463fd

Browse files
fix: address critical and high audit findings
CRITICAL: Drift detection β€” post_execute() now checks drift_score against drift_threshold and emits POLICY_VIOLATION on breach. HIGH: CrewAI tool interception β€” pre_execute() result now checked, raises PolicyViolationError when governance blocks a task. HIGH: Human approval enforcement β€” added require_human_approval check to anthropic_adapter and crewai_adapter (was OpenAI-only). MEDIUM: Exception handling β€” annotated bare except blocks with noqa comments explaining intentional suppression. Type safety: confidence and drift_score comparisons now guard against non-numeric types (e.g., MagicMock in tests). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent c8dbb63 commit 4c463fd

File tree

4 files changed

+38
-9
lines changed

4 files changed

+38
-9
lines changed

β€Žsrc/agent_os/integrations/anthropic_adapter.pyβ€Ž

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,11 @@ def create(self, **kwargs: Any) -> Any:
317317
f"Tool not allowed: {tool_name}"
318318
)
319319

320+
if self._kernel.policy.require_human_approval:
321+
raise PolicyViolationError(
322+
f"Tool '{tool_name}' requires human approval per governance policy"
323+
)
324+
320325
# Post-execute bookkeeping
321326
self._kernel.post_execute(self._ctx, response)
322327

β€Žsrc/agent_os/integrations/base.pyβ€Ž

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -801,8 +801,8 @@ def emit(self, event_type: GovernanceEventType, data: Dict[str, Any]) -> None:
801801
for cb in self._event_listeners.get(event_type, []):
802802
try:
803803
cb(data)
804-
except Exception:
805-
pass # Don't let listener errors break governance flow
804+
except Exception: # noqa: BLE001 β€” listener errors must not break governance flow
805+
pass
806806

807807
def pre_execute(self, ctx: ExecutionContext, input_data: Any) -> tuple[bool, Optional[str]]:
808808
"""
@@ -838,7 +838,7 @@ def pre_execute(self, ctx: ExecutionContext, input_data: Any) -> tuple[bool, Opt
838838
# Check confidence threshold
839839
if self.policy.confidence_threshold > 0.0:
840840
confidence = getattr(input_data, 'confidence', None)
841-
if confidence is not None and confidence < self.policy.confidence_threshold:
841+
if isinstance(confidence, (int, float)) and confidence < self.policy.confidence_threshold:
842842
reason = (
843843
f"Confidence {confidence:.2f} below threshold "
844844
f"{self.policy.confidence_threshold:.2f}"
@@ -850,12 +850,28 @@ def pre_execute(self, ctx: ExecutionContext, input_data: Any) -> tuple[bool, Opt
850850

851851
def post_execute(self, ctx: ExecutionContext, output_data: Any) -> tuple[bool, Optional[str]]:
852852
"""
853-
Post-execution validation.
853+
Post-execution validation including drift detection.
854854
855855
Returns (valid, reason) tuple.
856856
"""
857857
ctx.call_count += 1
858858

859+
# Drift detection: compare output against policy threshold
860+
if self.policy.drift_threshold > 0.0:
861+
drift_score = getattr(output_data, 'drift_score', None)
862+
if isinstance(drift_score, (int, float)) and drift_score > self.policy.drift_threshold:
863+
reason = (
864+
f"Drift score {drift_score:.2f} exceeds threshold "
865+
f"{self.policy.drift_threshold:.2f}"
866+
)
867+
self.emit(GovernanceEventType.POLICY_VIOLATION, {
868+
"agent_id": ctx.agent_id,
869+
"timestamp": datetime.now().isoformat(),
870+
"reason": reason,
871+
"drift_score": drift_score,
872+
})
873+
return False, reason
874+
859875
# Checkpoint if needed
860876
if ctx.call_count % self.policy.checkpoint_frequency == 0:
861877
checkpoint_id = f"checkpoint-{ctx.call_count}"

β€Žsrc/agent_os/integrations/crewai_adapter.pyβ€Ž

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
logger = logging.getLogger(__name__)
2020

21-
from .base import BaseIntegration, GovernancePolicy, ExecutionContext
21+
from .base import BaseIntegration, GovernancePolicy, ExecutionContext, PolicyViolationError
2222

2323
logger = logging.getLogger(__name__)
2424

@@ -121,9 +121,17 @@ def _wrap_agent(self, agent):
121121
def governed_execute(task, *args, **kwargs):
122122
task_id = getattr(task, 'id', None) or str(id(task))
123123
logger.info("Agent task execution started: crew_name=%s, task_id=%s", crew_name, task_id)
124-
self._kernel.pre_execute(self._ctx, task)
124+
if self._kernel.policy.require_human_approval:
125+
raise PolicyViolationError(
126+
f"Task '{task_id}' requires human approval per governance policy"
127+
)
128+
allowed, reason = self._kernel.pre_execute(self._ctx, task)
129+
if not allowed:
130+
raise PolicyViolationError(f"Task blocked: {reason}")
125131
result = original_execute(task, *args, **kwargs)
126-
self._kernel.post_execute(self._ctx, result)
132+
valid, drift_reason = self._kernel.post_execute(self._ctx, result)
133+
if not valid:
134+
logger.warning("Post-execute violation: crew_name=%s, task_id=%s, reason=%s", crew_name, task_id, drift_reason)
127135
logger.info("Agent task execution completed: crew_name=%s, task_id=%s", crew_name, task_id)
128136
return result
129137
agent.execute_task = governed_execute

β€Žsrc/agent_os/integrations/openai_adapter.pyβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,8 @@ def cancel_run(self, thread_id: str, run_id: str, client: Any):
252252
thread_id=thread_id,
253253
run_id=run_id
254254
)
255-
except Exception:
256-
pass # Run may already be complete
255+
except Exception: # noqa: BLE001 β€” best-effort cancel, run may already be complete
256+
pass
257257

258258
def is_cancelled(self, run_id: str) -> bool:
259259
"""Check whether a run has been cancelled via :meth:`cancel_run`.

0 commit comments

Comments
Β (0)