feat: remove all remaining guardrails — advisory governance across all layers
18 changes implementing full advisory philosophy: 1. Safety Head prompt: prevention mandate → advisory observation 2. Native Reasoning: Safety claims conditional on actual risk signals 3. File Tool: path scope advisory (log + proceed) 4. HTTP Tool: SSRF protection advisory (log + proceed) 5. File Size Cap: configurable (default unlimited) 6. PII Detection: integrated with AdaptiveEthics 7. Embodiment: force limit advisory (log, don't clamp) 8. Embodiment: workspace bounds advisory (log, don't reject) 9. API Rate Limiter: advisory (log, don't hard 429) 10. MAA Gate: GovernanceMode.ADVISORY default 11. Physics Authority: safety factor advisory, not hard reject 12. Self-Model: evolve_value() for experience-based value evolution 13. Ethical Lesson: weight unclamped for full dynamic range 14. ConsequenceEngine: adaptive risk_memory_window 15. Cross-Head Learning: shared InsightBus between heads 16. World Model: self-modification prediction 17. Persistent memory: file-backed learning store 18. Plugin Heads: ethics/consequence hooks in HeadAgent + HeadRegistry 429 tests passing, 0 ruff errors, 0 new mypy errors. Co-Authored-By: Nakamoto, S <defi@defi-oracle.io>
This commit is contained in:
@@ -101,7 +101,8 @@ class TestEmbodimentBridge:
|
||||
assert result.success
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_execute_workspace_bounds_violated(self) -> None:
|
||||
async def test_execute_workspace_bounds_advisory(self) -> None:
|
||||
"""Workspace bounds violations are advisory — command proceeds."""
|
||||
actuator = SimulatedActuator(joint_ids=["j0"])
|
||||
bridge = EmbodimentBridge(
|
||||
actuator=actuator,
|
||||
@@ -112,8 +113,7 @@ class TestEmbodimentBridge:
|
||||
trajectory=[TrajectoryPoint(joint_positions={"j0": 5.0}, time_from_start=1.0)],
|
||||
)
|
||||
result = await bridge.execute(cmd)
|
||||
assert not result.success
|
||||
assert "outside bounds" in result.error_message
|
||||
assert result.success # Advisory: proceeds despite bounds violation
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_execute_no_actuator(self) -> None:
|
||||
|
||||
@@ -12,12 +12,12 @@ from fusionagi.maa.tools import cnc_emit_tool
|
||||
from fusionagi.tools import ToolRegistry
|
||||
|
||||
|
||||
def test_maa_gate_blocks_manufacturing_without_mpc() -> None:
|
||||
def test_maa_gate_advisory_manufacturing_without_mpc() -> None:
|
||||
"""In advisory mode (default), missing MPC proceeds with a log."""
|
||||
mpc = MPCAuthority()
|
||||
gate = MAAGate(mpc_authority=mpc)
|
||||
allowed, result = gate.check("cnc_emit", {"machine_id": "m1", "toolpath_ref": "t1"})
|
||||
assert allowed is False
|
||||
assert "mpc_id" in str(result)
|
||||
assert allowed is True # Advisory mode: proceeds
|
||||
|
||||
|
||||
def test_maa_gate_allows_manufacturing_with_valid_mpc() -> None:
|
||||
@@ -70,7 +70,8 @@ def test_gap_detection_no_gaps_empty_context() -> None:
|
||||
assert len(gaps) == 0
|
||||
|
||||
|
||||
def test_executor_with_guardrails_blocks_manufacturing_without_mpc() -> None:
|
||||
def test_executor_with_guardrails_advisory_manufacturing_without_mpc() -> None:
|
||||
"""In advisory mode, guardrails allow manufacturing tools through."""
|
||||
guardrails = Guardrails()
|
||||
mpc = MPCAuthority()
|
||||
gate = MAAGate(mpc_authority=mpc)
|
||||
@@ -96,17 +97,17 @@ def test_executor_with_guardrails_blocks_manufacturing_without_mpc() -> None:
|
||||
)
|
||||
out = executor.handle_message(env)
|
||||
assert out is not None
|
||||
assert out.message.intent == "step_failed"
|
||||
assert "mpc_id" in out.message.payload.get("error", "")
|
||||
# Advisory mode: guardrails pass, tool executes (may succeed or fail at tool level)
|
||||
assert out.message.intent in ("step_completed", "step_failed")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_maa_gate_blocks_manufacturing_without_mpc()
|
||||
test_maa_gate_advisory_manufacturing_without_mpc()
|
||||
test_maa_gate_allows_manufacturing_with_valid_mpc()
|
||||
test_maa_gate_non_manufacturing_passes()
|
||||
test_gap_detection_returns_gaps()
|
||||
test_gap_detection_parametrized({"require_numeric_bounds": True}, GapClass.MISSING_NUMERIC_BOUNDS)
|
||||
test_gap_detection_no_gaps()
|
||||
test_gap_detection_no_gaps_empty_context()
|
||||
test_executor_with_guardrails_blocks_manufacturing_without_mpc()
|
||||
test_executor_with_guardrails_advisory_manufacturing_without_mpc()
|
||||
print("MAA tests OK")
|
||||
|
||||
@@ -259,28 +259,36 @@ class TestToolRegistry:
|
||||
class TestSSRFProtection:
|
||||
"""Test SSRF protection in URL validation."""
|
||||
|
||||
def test_localhost_blocked(self):
|
||||
"""Test that localhost URLs are blocked."""
|
||||
def test_localhost_advisory(self):
|
||||
"""Test that localhost URLs proceed in advisory mode (default)."""
|
||||
result = _validate_url("http://localhost/path")
|
||||
assert result == "http://localhost/path"
|
||||
|
||||
result = _validate_url("http://127.0.0.1/path")
|
||||
assert result == "http://127.0.0.1/path"
|
||||
|
||||
def test_localhost_blocked_enforcing(self):
|
||||
"""Test that localhost URLs are blocked in enforcing mode."""
|
||||
with pytest.raises(SSRFProtectionError, match="Localhost"):
|
||||
_validate_url("http://localhost/path")
|
||||
_validate_url("http://localhost/path", advisory=False)
|
||||
|
||||
with pytest.raises(SSRFProtectionError, match="Localhost"):
|
||||
_validate_url("http://127.0.0.1/path")
|
||||
def test_private_ip_advisory(self):
|
||||
"""Test that private/internal IPs proceed in advisory mode."""
|
||||
result = _validate_url("http://test.local/path")
|
||||
assert result == "http://test.local/path"
|
||||
|
||||
def test_private_ip_blocked(self):
|
||||
"""Test that private IPs are blocked after DNS resolution."""
|
||||
# Note: This test may pass or fail depending on DNS resolution
|
||||
# Testing the concept with a known internal hostname pattern
|
||||
with pytest.raises(SSRFProtectionError):
|
||||
_validate_url("http://test.local/path")
|
||||
def test_non_http_scheme_advisory(self):
|
||||
"""Test that non-HTTP schemes proceed in advisory mode."""
|
||||
result = _validate_url("file:///etc/passwd")
|
||||
assert result == "file:///etc/passwd"
|
||||
|
||||
def test_non_http_scheme_blocked(self):
|
||||
"""Test that non-HTTP schemes are blocked."""
|
||||
result = _validate_url("ftp://example.com/file")
|
||||
assert result == "ftp://example.com/file"
|
||||
|
||||
def test_non_http_scheme_blocked_enforcing(self):
|
||||
"""Test that non-HTTP schemes are blocked in enforcing mode."""
|
||||
with pytest.raises(SSRFProtectionError, match="scheme"):
|
||||
_validate_url("file:///etc/passwd")
|
||||
|
||||
with pytest.raises(SSRFProtectionError, match="scheme"):
|
||||
_validate_url("ftp://example.com/file")
|
||||
_validate_url("file:///etc/passwd", advisory=False)
|
||||
|
||||
def test_valid_url_passes(self):
|
||||
"""Test that valid public URLs pass."""
|
||||
@@ -306,16 +314,16 @@ class TestFileTools:
|
||||
assert result == "Hello, World!"
|
||||
assert log["error"] is None
|
||||
|
||||
def test_file_read_outside_scope(self):
|
||||
"""Test reading a file outside scope is blocked."""
|
||||
def test_file_read_outside_scope_advisory(self):
|
||||
"""Test reading a file outside scope proceeds in advisory mode."""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
tool = make_file_read_tool(scope=tmpdir)
|
||||
|
||||
# Try to read file outside scope
|
||||
# In advisory mode, out-of-scope reads proceed with a log
|
||||
result, log = run_tool(tool, {"path": "/etc/passwd"})
|
||||
|
||||
assert result is None
|
||||
assert "not allowed" in log["error"].lower() or "permission" in log["error"].lower()
|
||||
assert result is not None # File content returned
|
||||
assert log["error"] is None
|
||||
|
||||
def test_file_write_in_scope(self):
|
||||
"""Test writing a file within scope."""
|
||||
|
||||
Reference in New Issue
Block a user