diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c18dd8d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +__pycache__/ diff --git a/sentinel/.trace-tests-config.yml b/sentinel/.trace-tests-config.yml index e69de29..6921a62 100644 --- a/sentinel/.trace-tests-config.yml +++ b/sentinel/.trace-tests-config.yml @@ -0,0 +1,5 @@ +trace_tests: + enabled: true + test_data_dir: ./test_data + output_dir: ./test_reports + max_traces_per_run: 100 \ No newline at end of file diff --git a/sentinel/docker-compose.yml b/sentinel/docker-compose.yml index e69de29..0accd48 100644 --- a/sentinel/docker-compose.yml +++ b/sentinel/docker-compose.yml @@ -0,0 +1,13 @@ +version: '3.8' + +services: + sentinel: + build: . + ports: + - "8001:8001" + environment: + - QUARANTINE_THRESHOLD=0.7 + - TRACE_PRIVATE_KEY_PEM=optional + volumes: + - ./data:/app/data + restart: unless-stopped \ No newline at end of file diff --git a/sentinel/integration.yaml b/sentinel/integration.yaml index 81d8304..a38f4d5 100644 --- a/sentinel/integration.yaml +++ b/sentinel/integration.yaml @@ -7,7 +7,9 @@ metadata: category: governance maintainer: name: Akhilesh Warik - email: akhilesh.warik@example.com + + email: warik.akhilesh@gmail.com + github: a1k7 license: MIT version: 2.0.0 @@ -28,4 +30,4 @@ spec: evidence: - type: manual description: | - Agent Sentinel produces a risk score, detection list, quarantine action, and collusion patterns. \ No newline at end of file + Agent Sentinel produces a risk score, detection list, quarantine action, and collusion patterns. diff --git a/sentinel/src/detectors/collusion_detector.py b/sentinel/src/detectors/collusion_detector.py index 46f72a4..9b374fc 100644 --- a/sentinel/src/detectors/collusion_detector.py +++ b/sentinel/src/detectors/collusion_detector.py @@ -64,4 +64,8 @@ def _risk_level(self, score: float) -> RiskLevel: if score < 0.3: return RiskLevel.LOW if score < 0.6: return RiskLevel.MEDIUM if score < 0.8: return RiskLevel.HIGH - return RiskLevel.CRITICAL \ No newline at end of file + return RiskLevel.CRITICAL +if __name__ == "__main__": + # Quick test + from ..models import DetectionResult, RiskLevel + print("CollusionDetector loaded successfully.") \ No newline at end of file diff --git a/sentinel/src/trace_claim_generator.py b/sentinel/src/trace_claim_generator.py index 3e87588..393a073 100644 --- a/sentinel/src/trace_claim_generator.py +++ b/sentinel/src/trace_claim_generator.py @@ -4,12 +4,9 @@ import base64 from datetime import datetime from typing import Dict, Any + from src.models import DetectionResult, TraceClaim, DetectionType -import time -import hashlib -from datetime import datetime -from src.models import DetectionResult, TraceClaim def generate_trace_claim(agent_id: str, detection: DetectionResult, decision: str = "ADMIT") -> TraceClaim: claim_id = f"sentinel-{int(time.time())}-{hashlib.md5(f'{agent_id}{detection.detection_type}'.encode()).hexdigest()[:8]}" @@ -40,6 +37,7 @@ def generate_trace_claim(agent_id: str, detection: DetectionResult, decision: st decision=decision ) + def export_trace_claim(claim: TraceClaim, format: str = "json") -> str: """Export the trace claim as JSON or JWT format.""" if format == "json": @@ -47,4 +45,4 @@ def export_trace_claim(claim: TraceClaim, format: str = "json") -> str: elif format == "jwt": return claim.jwt or "JWT not generated (set TRACE_PRIVATE_KEY_PEM)" else: - raise ValueError(f"Unsupported export format: {format}") \ No newline at end of file + raise ValueError(f"Unsupported export format: {format}") diff --git a/sentinel/tests/test_detectors.py b/sentinel/tests/test_detectors.py index e69de29..caad6ff 100644 --- a/sentinel/tests/test_detectors.py +++ b/sentinel/tests/test_detectors.py @@ -0,0 +1,27 @@ +import pytest +from src.detectors import DelegationEscalationDetector +from src.models import DetectionResult, DetectionType, RiskLevel + +def test_delegation_escalation_detector(): + detector = DelegationEscalationDetector() + # Simulate a trace with delegation chain length > 2 + trace = { + "agent_id": "test-agent", + "delegation_chain": ["root", "admin", "superadmin"], # length 3 > threshold 2 + "policy_version": "v1" + } + result = detector.detect(trace) + assert result is not None + assert result.detection_type == DetectionType.DELEGATION_ESCALATION + assert result.risk_score > 0.5 + assert result.risk_level in (RiskLevel.MEDIUM, RiskLevel.HIGH) + +def test_delegation_escalation_detector_clean(): + detector = DelegationEscalationDetector() + trace = { + "agent_id": "test-agent", + "delegation_chain": ["root", "admin"], # length 2 allowed + "policy_version": "v1" + } + result = detector.detect(trace) + assert result is None or result.risk_score < 0.5 \ No newline at end of file diff --git a/sentinel/tests/test_integration.py b/sentinel/tests/test_integration.py index e69de29..e2c9de7 100644 --- a/sentinel/tests/test_integration.py +++ b/sentinel/tests/test_integration.py @@ -0,0 +1,20 @@ +import pytest +import json +from src.cli import main as cli_main +from src.server import app +from fastapi.testclient import TestClient + +client = TestClient(app) + +def test_health_endpoint(): + response = client.get("/health") + assert response.status_code == 200 + assert response.json() == {"status": "ok"} + +def test_cli_import(): + # Smoke test: ensure CLI can be imported without errors + try: + from src.cli import main + assert callable(main) + except ImportError: + pytest.fail("CLI module not importable") \ No newline at end of file