"""Helper utilities for security hardening Robot integration tests. Covers SEC1: eval()/exec() removal from stream_router.py. - Named operation registry (SimpleToolAgent._SAFE_OPERATIONS) - Named transform registry (ReactiveStreamRouter._TRANSFORM_REGISTRY) - Rejection of code blocks and unregistered transforms """ from __future__ import annotations import sys from cleveragents.core.exceptions import StreamRoutingError from cleveragents.reactive.stream_router import ( ReactiveStreamRouter, SimpleToolAgent, StreamConfig, StreamType, ) def _named_operations_work() -> None: """Integration test: registered named operations execute correctly.""" # Operations are configured via tool dicts, not message metadata agent_upper = SimpleToolAgent(tools=[{"operation": "uppercase"}]) result = agent_upper.process("hello world", {}, {}) assert result == "HELLO WORLD", f"Expected 'HELLO WORLD', got {result}" agent_strip = SimpleToolAgent(tools=[{"operation": "strip"}]) result2 = agent_strip.process(" HELLO ", {}, {}) assert result2 == "HELLO", f"Expected 'HELLO', got {result2}" agent_lower = SimpleToolAgent(tools=[{"operation": "lowercase"}]) result3 = agent_lower.process("HELLO", {}, {}) assert result3 == "hello", f"Expected 'hello', got {result3}" print("named-operations-ok") def _code_blocks_rejected() -> None: """Integration test: code blocks are rejected (no eval/exec).""" # Code blocks are in the tool config, not metadata agent = SimpleToolAgent(tools=[{"code": "import os; os.system('echo pwned')"}]) try: agent.process("test", {}, {}) print("FAIL: Expected StreamRoutingError for code block") return except StreamRoutingError: pass # Attempt with import injection agent2 = SimpleToolAgent(tools=[{"code": "__import__('subprocess').call(['ls'])"}]) try: agent2.process("test", {}, {}) print("FAIL: Expected StreamRoutingError for import code block") return except StreamRoutingError: pass print("code-blocks-rejected-ok") def _custom_operation_registration() -> None: """Integration test: custom operations can be registered and used.""" # Register a custom operation (takes content, meta, ctx) SimpleToolAgent.register_operation( "reverse", lambda content, meta, ctx: content[::-1] ) agent = SimpleToolAgent(tools=[{"operation": "reverse"}]) result = agent.process("hello", {}, {}) assert result == "olleh", f"Expected 'olleh', got {result}" print("custom-operation-ok") def _unregistered_transform_rejected() -> None: """Integration test: unregistered transform expressions are rejected.""" router = ReactiveStreamRouter() # Create a stream with an unregistered fn (lambda expression) config = StreamConfig( name="test_stream", type=StreamType.COLD, operators=[ { "type": "transform", "params": {"fn": "lambda x: x.upper()"}, } ], ) # This should raise StreamRoutingError during stream creation try: router.create_stream(config) print("FAIL: Expected StreamRoutingError for unregistered transform") return except StreamRoutingError: pass except Exception: # Any error rejecting unregistered transforms is acceptable pass print("unregistered-transform-rejected-ok") def _registered_transform_works() -> None: """Integration test: registered transforms work correctly.""" # Register a named transform ReactiveStreamRouter.register_transform("shout", lambda x: x.upper() + "!") # Verify it's in the registry assert "shout" in ReactiveStreamRouter._TRANSFORM_REGISTRY assert ReactiveStreamRouter._TRANSFORM_REGISTRY["shout"]("hello") == "HELLO!" print("registered-transform-ok") def _identity_operation_default() -> None: """Integration test: identity is a valid named operation.""" agent = SimpleToolAgent(tools=[{"operation": "identity"}]) result = agent.process("unchanged", {}, {}) assert result == "unchanged", f"Expected 'unchanged', got {result}" # No tools means passthrough agent_empty = SimpleToolAgent(tools=[]) result2 = agent_empty.process("unchanged", {}, {}) assert result2 == "unchanged", f"Expected 'unchanged', got {result2}" print("identity-default-ok") def main() -> None: if len(sys.argv) < 2: raise SystemExit("Expected command argument") command = sys.argv[1] commands = { "named-operations": _named_operations_work, "code-blocks-rejected": _code_blocks_rejected, "custom-operation": _custom_operation_registration, "unregistered-transform": _unregistered_transform_rejected, "registered-transform": _registered_transform_works, "identity-default": _identity_operation_default, } if command not in commands: raise SystemExit(f"Unknown command: {command}") commands[command]() if __name__ == "__main__": main()