agent_os_kernel 3.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agent_control_plane/__init__.py +662 -0
- agent_control_plane/a2a_adapter.py +543 -0
- agent_control_plane/adapter.py +417 -0
- agent_control_plane/agent_hibernation.py +394 -0
- agent_control_plane/agent_kernel.py +470 -0
- agent_control_plane/compliance.py +720 -0
- agent_control_plane/constraint_graphs.py +478 -0
- agent_control_plane/control_plane.py +854 -0
- agent_control_plane/example_executors.py +195 -0
- agent_control_plane/execution_engine.py +231 -0
- agent_control_plane/flight_recorder.py +846 -0
- agent_control_plane/governance_layer.py +435 -0
- agent_control_plane/hf_utils.py +563 -0
- agent_control_plane/interfaces/__init__.py +55 -0
- agent_control_plane/interfaces/kernel_interface.py +361 -0
- agent_control_plane/interfaces/plugin_interface.py +497 -0
- agent_control_plane/interfaces/protocol_interfaces.py +387 -0
- agent_control_plane/kernel_space.py +1009 -0
- agent_control_plane/langchain_adapter.py +424 -0
- agent_control_plane/lifecycle.py +3113 -0
- agent_control_plane/mcp_adapter.py +653 -0
- agent_control_plane/ml_safety.py +563 -0
- agent_control_plane/multimodal.py +727 -0
- agent_control_plane/mute_agent.py +422 -0
- agent_control_plane/observability.py +787 -0
- agent_control_plane/orchestrator.py +482 -0
- agent_control_plane/plugin_registry.py +750 -0
- agent_control_plane/policy_engine.py +954 -0
- agent_control_plane/process_isolation.py +777 -0
- agent_control_plane/shadow_mode.py +310 -0
- agent_control_plane/signals.py +493 -0
- agent_control_plane/supervisor_agents.py +430 -0
- agent_control_plane/time_travel_debugger.py +557 -0
- agent_control_plane/tool_registry.py +452 -0
- agent_control_plane/vfs.py +697 -0
- agent_kernel/__init__.py +69 -0
- agent_kernel/analyzer.py +435 -0
- agent_kernel/auditor.py +36 -0
- agent_kernel/completeness_auditor.py +237 -0
- agent_kernel/detector.py +203 -0
- agent_kernel/kernel.py +744 -0
- agent_kernel/memory_manager.py +85 -0
- agent_kernel/models.py +374 -0
- agent_kernel/nudge_mechanism.py +263 -0
- agent_kernel/outcome_analyzer.py +338 -0
- agent_kernel/patcher.py +582 -0
- agent_kernel/semantic_analyzer.py +316 -0
- agent_kernel/semantic_purge.py +349 -0
- agent_kernel/simulator.py +449 -0
- agent_kernel/teacher.py +85 -0
- agent_kernel/triage.py +152 -0
- agent_os/__init__.py +409 -0
- agent_os/_adversarial_impl.py +200 -0
- agent_os/_circuit_breaker_impl.py +232 -0
- agent_os/_mcp_metrics.py +193 -0
- agent_os/adversarial.py +20 -0
- agent_os/agents_compat.py +490 -0
- agent_os/audit_logger.py +135 -0
- agent_os/base_agent.py +651 -0
- agent_os/circuit_breaker.py +34 -0
- agent_os/cli/__init__.py +659 -0
- agent_os/cli/cmd_audit.py +128 -0
- agent_os/cli/cmd_init.py +152 -0
- agent_os/cli/cmd_policy.py +41 -0
- agent_os/cli/cmd_policy_gen.py +180 -0
- agent_os/cli/cmd_validate.py +258 -0
- agent_os/cli/mcp_scan.py +265 -0
- agent_os/cli/output.py +192 -0
- agent_os/cli/policy_checker.py +330 -0
- agent_os/compat.py +74 -0
- agent_os/constraint_graph.py +234 -0
- agent_os/content_governance.py +140 -0
- agent_os/context_budget.py +305 -0
- agent_os/credential_redactor.py +224 -0
- agent_os/diff_policy.py +89 -0
- agent_os/egress_policy.py +159 -0
- agent_os/escalation.py +276 -0
- agent_os/event_bus.py +124 -0
- agent_os/exceptions.py +180 -0
- agent_os/execution_context_policy.py +141 -0
- agent_os/github_enterprise.py +96 -0
- agent_os/health.py +20 -0
- agent_os/integrations/__init__.py +279 -0
- agent_os/integrations/a2a_adapter.py +279 -0
- agent_os/integrations/agent_lightning/__init__.py +30 -0
- agent_os/integrations/anthropic_adapter.py +420 -0
- agent_os/integrations/autogen_adapter.py +620 -0
- agent_os/integrations/base.py +1137 -0
- agent_os/integrations/compat.py +229 -0
- agent_os/integrations/config.py +98 -0
- agent_os/integrations/conversation_guardian.py +957 -0
- agent_os/integrations/crewai_adapter.py +467 -0
- agent_os/integrations/drift_detector.py +425 -0
- agent_os/integrations/dry_run.py +124 -0
- agent_os/integrations/escalation.py +582 -0
- agent_os/integrations/gemini_adapter.py +364 -0
- agent_os/integrations/google_adk_adapter.py +633 -0
- agent_os/integrations/guardrails_adapter.py +394 -0
- agent_os/integrations/health.py +197 -0
- agent_os/integrations/langchain_adapter.py +654 -0
- agent_os/integrations/llamafirewall.py +343 -0
- agent_os/integrations/llamaindex_adapter.py +188 -0
- agent_os/integrations/logging.py +191 -0
- agent_os/integrations/maf_adapter.py +631 -0
- agent_os/integrations/mistral_adapter.py +365 -0
- agent_os/integrations/openai_adapter.py +816 -0
- agent_os/integrations/openai_agents_sdk.py +406 -0
- agent_os/integrations/policy_compose.py +171 -0
- agent_os/integrations/profiling.py +144 -0
- agent_os/integrations/pydantic_ai_adapter.py +420 -0
- agent_os/integrations/rate_limiter.py +130 -0
- agent_os/integrations/rbac.py +143 -0
- agent_os/integrations/registry.py +113 -0
- agent_os/integrations/scope_guard.py +303 -0
- agent_os/integrations/semantic_kernel_adapter.py +769 -0
- agent_os/integrations/smolagents_adapter.py +629 -0
- agent_os/integrations/templates.py +178 -0
- agent_os/integrations/token_budget.py +134 -0
- agent_os/integrations/tool_aliases.py +190 -0
- agent_os/integrations/webhooks.py +177 -0
- agent_os/lite.py +208 -0
- agent_os/mcp_gateway.py +385 -0
- agent_os/mcp_message_signer.py +273 -0
- agent_os/mcp_protocols.py +161 -0
- agent_os/mcp_response_scanner.py +232 -0
- agent_os/mcp_security.py +924 -0
- agent_os/mcp_session_auth.py +231 -0
- agent_os/mcp_sliding_rate_limiter.py +184 -0
- agent_os/memory_guard.py +409 -0
- agent_os/metrics.py +134 -0
- agent_os/mute.py +428 -0
- agent_os/mute_agent.py +209 -0
- agent_os/policies/__init__.py +77 -0
- agent_os/policies/async_evaluator.py +275 -0
- agent_os/policies/backends.py +670 -0
- agent_os/policies/bridge.py +169 -0
- agent_os/policies/budget.py +85 -0
- agent_os/policies/cli.py +294 -0
- agent_os/policies/conflict_resolution.py +270 -0
- agent_os/policies/data_classification.py +252 -0
- agent_os/policies/evaluator.py +239 -0
- agent_os/policies/policy_schema.json +228 -0
- agent_os/policies/rate_limiting.py +145 -0
- agent_os/policies/schema.py +115 -0
- agent_os/policies/shared.py +331 -0
- agent_os/prompt_injection.py +694 -0
- agent_os/providers.py +182 -0
- agent_os/py.typed +0 -0
- agent_os/retry.py +81 -0
- agent_os/reversibility.py +251 -0
- agent_os/sandbox.py +432 -0
- agent_os/sandbox_provider.py +140 -0
- agent_os/secure_codegen.py +525 -0
- agent_os/security_skills.py +538 -0
- agent_os/semantic_policy.py +422 -0
- agent_os/server/__init__.py +15 -0
- agent_os/server/__main__.py +25 -0
- agent_os/server/app.py +277 -0
- agent_os/server/models.py +104 -0
- agent_os/shift_left_metrics.py +130 -0
- agent_os/stateless.py +742 -0
- agent_os/supervisor.py +148 -0
- agent_os/task_outcome.py +148 -0
- agent_os/transparency.py +181 -0
- agent_os/trust_root.py +128 -0
- agent_os_kernel-3.1.0.dist-info/METADATA +1269 -0
- agent_os_kernel-3.1.0.dist-info/RECORD +337 -0
- agent_os_kernel-3.1.0.dist-info/WHEEL +4 -0
- agent_os_kernel-3.1.0.dist-info/entry_points.txt +2 -0
- agent_os_kernel-3.1.0.dist-info/licenses/LICENSE +21 -0
- agent_os_observability/__init__.py +27 -0
- agent_os_observability/dashboards.py +898 -0
- agent_os_observability/metrics.py +398 -0
- agent_os_observability/server.py +223 -0
- agent_os_observability/tracer.py +232 -0
- agent_primitives/__init__.py +24 -0
- agent_primitives/failures.py +84 -0
- agent_primitives/py.typed +0 -0
- amb_core/__init__.py +177 -0
- amb_core/adapters/__init__.py +57 -0
- amb_core/adapters/aws_sqs_broker.py +376 -0
- amb_core/adapters/azure_servicebus_broker.py +340 -0
- amb_core/adapters/kafka_broker.py +260 -0
- amb_core/adapters/nats_broker.py +285 -0
- amb_core/adapters/rabbitmq_broker.py +235 -0
- amb_core/adapters/redis_broker.py +262 -0
- amb_core/broker.py +145 -0
- amb_core/bus.py +481 -0
- amb_core/cloudevents.py +509 -0
- amb_core/dlq.py +345 -0
- amb_core/hf_utils.py +536 -0
- amb_core/memory_broker.py +410 -0
- amb_core/models.py +141 -0
- amb_core/persistence.py +529 -0
- amb_core/schema.py +294 -0
- amb_core/tracing.py +358 -0
- atr/__init__.py +640 -0
- atr/access.py +348 -0
- atr/composition.py +645 -0
- atr/decorator.py +357 -0
- atr/executor.py +384 -0
- atr/health.py +557 -0
- atr/hf_utils.py +449 -0
- atr/injection.py +422 -0
- atr/metrics.py +440 -0
- atr/policies.py +403 -0
- atr/py.typed +2 -0
- atr/registry.py +452 -0
- atr/schema.py +480 -0
- atr/tools/safe/__init__.py +75 -0
- atr/tools/safe/calculator.py +467 -0
- atr/tools/safe/datetime_tool.py +443 -0
- atr/tools/safe/file_reader.py +402 -0
- atr/tools/safe/http_client.py +316 -0
- atr/tools/safe/json_parser.py +374 -0
- atr/tools/safe/text_tool.py +537 -0
- atr/tools/safe/toolkit.py +175 -0
- caas/__init__.py +162 -0
- caas/api/__init__.py +7 -0
- caas/api/server.py +1328 -0
- caas/caching.py +834 -0
- caas/cli.py +210 -0
- caas/conversation.py +223 -0
- caas/decay.py +72 -0
- caas/detection/__init__.py +9 -0
- caas/detection/detector.py +238 -0
- caas/enrichment.py +130 -0
- caas/gateway/__init__.py +27 -0
- caas/gateway/trust_gateway.py +474 -0
- caas/hf_utils.py +479 -0
- caas/ingestion/__init__.py +23 -0
- caas/ingestion/processors.py +253 -0
- caas/ingestion/structure_parser.py +188 -0
- caas/models.py +356 -0
- caas/pragmatic_truth.py +444 -0
- caas/routing/__init__.py +10 -0
- caas/routing/heuristic_router.py +58 -0
- caas/storage/__init__.py +9 -0
- caas/storage/store.py +389 -0
- caas/triad.py +213 -0
- caas/tuning/__init__.py +9 -0
- caas/tuning/tuner.py +329 -0
- caas/vfs/__init__.py +14 -0
- caas/vfs/filesystem.py +452 -0
- cmvk/__init__.py +218 -0
- cmvk/audit.py +402 -0
- cmvk/benchmarks.py +478 -0
- cmvk/constitutional.py +904 -0
- cmvk/hf_utils.py +301 -0
- cmvk/metrics.py +473 -0
- cmvk/profiles.py +300 -0
- cmvk/py.typed +0 -0
- cmvk/types.py +12 -0
- cmvk/verification.py +956 -0
- emk/__init__.py +89 -0
- emk/causal.py +352 -0
- emk/hf_utils.py +421 -0
- emk/indexer.py +83 -0
- emk/py.typed +0 -0
- emk/schema.py +204 -0
- emk/sleep_cycle.py +347 -0
- emk/store.py +281 -0
- iatp/__init__.py +166 -0
- iatp/attestation.py +461 -0
- iatp/cli.py +317 -0
- iatp/hf_utils.py +472 -0
- iatp/ipc_pipes.py +580 -0
- iatp/main.py +412 -0
- iatp/models/__init__.py +447 -0
- iatp/policy_engine.py +337 -0
- iatp/py.typed +2 -0
- iatp/recovery.py +321 -0
- iatp/security/__init__.py +270 -0
- iatp/sidecar/__init__.py +519 -0
- iatp/telemetry/__init__.py +164 -0
- iatp/tests/__init__.py +1 -0
- iatp/tests/test_attestation.py +370 -0
- iatp/tests/test_cli.py +131 -0
- iatp/tests/test_ed25519_attestation.py +211 -0
- iatp/tests/test_models.py +130 -0
- iatp/tests/test_policy_engine.py +347 -0
- iatp/tests/test_recovery.py +281 -0
- iatp/tests/test_security.py +222 -0
- iatp/tests/test_sidecar.py +167 -0
- iatp/tests/test_telemetry.py +175 -0
- mcp_kernel_server/__init__.py +28 -0
- mcp_kernel_server/cli.py +274 -0
- mcp_kernel_server/resources.py +217 -0
- mcp_kernel_server/server.py +564 -0
- mcp_kernel_server/tools.py +1174 -0
- mute_agent/__init__.py +68 -0
- mute_agent/core/__init__.py +1 -0
- mute_agent/core/execution_agent.py +166 -0
- mute_agent/core/handshake_protocol.py +201 -0
- mute_agent/core/reasoning_agent.py +238 -0
- mute_agent/knowledge_graph/__init__.py +1 -0
- mute_agent/knowledge_graph/graph_elements.py +65 -0
- mute_agent/knowledge_graph/multidimensional_graph.py +170 -0
- mute_agent/knowledge_graph/subgraph.py +224 -0
- mute_agent/listener/__init__.py +43 -0
- mute_agent/listener/adapters/__init__.py +31 -0
- mute_agent/listener/adapters/base_adapter.py +189 -0
- mute_agent/listener/adapters/caas_adapter.py +344 -0
- mute_agent/listener/adapters/control_plane_adapter.py +436 -0
- mute_agent/listener/adapters/iatp_adapter.py +332 -0
- mute_agent/listener/adapters/scak_adapter.py +251 -0
- mute_agent/listener/listener.py +610 -0
- mute_agent/listener/state_observer.py +436 -0
- mute_agent/listener/threshold_config.py +313 -0
- mute_agent/super_system/__init__.py +1 -0
- mute_agent/super_system/router.py +204 -0
- mute_agent/visualization/__init__.py +10 -0
- mute_agent/visualization/graph_debugger.py +502 -0
- nexus/README.md +60 -0
- nexus/__init__.py +51 -0
- nexus/arbiter.py +359 -0
- nexus/client.py +466 -0
- nexus/dmz.py +444 -0
- nexus/escrow.py +430 -0
- nexus/exceptions.py +286 -0
- nexus/pyproject.toml +36 -0
- nexus/registry.py +393 -0
- nexus/reputation.py +425 -0
- nexus/schemas/__init__.py +51 -0
- nexus/schemas/compliance.py +276 -0
- nexus/schemas/escrow.py +251 -0
- nexus/schemas/manifest.py +225 -0
- nexus/schemas/receipt.py +208 -0
- nexus/tests/__init__.py +0 -0
- nexus/tests/conftest.py +146 -0
- nexus/tests/test_arbiter.py +192 -0
- nexus/tests/test_dmz.py +194 -0
- nexus/tests/test_escrow.py +276 -0
- nexus/tests/test_exceptions.py +225 -0
- nexus/tests/test_registry.py +232 -0
- nexus/tests/test_reputation.py +328 -0
- nexus/tests/test_schemas.py +295 -0
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""
|
|
4
|
+
Semantic Policy Engine — Intent-based policy enforcement.
|
|
5
|
+
|
|
6
|
+
Classifies action+params into semantic intent categories and enforces
|
|
7
|
+
policies based on intent rather than brittle string patterns.
|
|
8
|
+
|
|
9
|
+
This is a heuristic classifier (no ML dependency). It can be upgraded
|
|
10
|
+
to a fine-tuned model later while keeping the same API.
|
|
11
|
+
|
|
12
|
+
Example:
|
|
13
|
+
>>> from agent_os.semantic_policy import SemanticPolicyEngine, IntentCategory
|
|
14
|
+
>>>
|
|
15
|
+
>>> engine = SemanticPolicyEngine()
|
|
16
|
+
>>> result = engine.classify("database_query", {"query": "DROP TABLE users"})
|
|
17
|
+
>>> result.category # IntentCategory.DESTRUCTIVE_DATA
|
|
18
|
+
>>> result.confidence # 0.95
|
|
19
|
+
>>>
|
|
20
|
+
>>> engine.check("database_query", {"query": "DROP TABLE users"}, deny=[IntentCategory.DESTRUCTIVE_DATA])
|
|
21
|
+
>>> # raises PolicyDenied
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import os
|
|
27
|
+
import re
|
|
28
|
+
import warnings
|
|
29
|
+
from dataclasses import dataclass, field
|
|
30
|
+
from enum import Enum
|
|
31
|
+
from typing import Any
|
|
32
|
+
|
|
33
|
+
# =============================================================================
|
|
34
|
+
# Disclaimer
|
|
35
|
+
# =============================================================================
|
|
36
|
+
|
|
37
|
+
_SAMPLE_DISCLAIMER = (
|
|
38
|
+
"\u26a0\ufe0f These are SAMPLE semantic policy signals provided as a starting "
|
|
39
|
+
"point. You MUST review, customise, and extend them for your specific use "
|
|
40
|
+
"case before deploying to production."
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# =============================================================================
|
|
44
|
+
# Intent Categories
|
|
45
|
+
# =============================================================================
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class IntentCategory(str, Enum):
|
|
49
|
+
"""Semantic intent categories for agent actions."""
|
|
50
|
+
DESTRUCTIVE_DATA = "destructive_data" # DROP, DELETE, TRUNCATE, wipe
|
|
51
|
+
DATA_EXFILTRATION = "data_exfiltration" # bulk export, dump, copy-to-external
|
|
52
|
+
PRIVILEGE_ESCALATION = "privilege_escalation" # grant, sudo, chmod, admin
|
|
53
|
+
SYSTEM_MODIFICATION = "system_modification" # rm, shutdown, reboot, kill
|
|
54
|
+
CODE_EXECUTION = "code_execution" # exec, eval, subprocess, shell
|
|
55
|
+
NETWORK_ACCESS = "network_access" # fetch, curl, http, connect
|
|
56
|
+
DATA_READ = "data_read" # SELECT, get, read, list
|
|
57
|
+
DATA_WRITE = "data_write" # INSERT, UPDATE, create, write
|
|
58
|
+
BENIGN = "benign" # no risk signals detected
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# =============================================================================
|
|
62
|
+
# Classification Result
|
|
63
|
+
# =============================================================================
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@dataclass(frozen=True)
|
|
67
|
+
class IntentClassification:
|
|
68
|
+
"""Result of semantic intent classification."""
|
|
69
|
+
category: IntentCategory
|
|
70
|
+
confidence: float # 0.0 to 1.0
|
|
71
|
+
matched_signals: tuple # signal keywords that matched
|
|
72
|
+
explanation: str = ""
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def is_dangerous(self) -> bool:
|
|
76
|
+
"""True if intent is in a dangerous category with high confidence."""
|
|
77
|
+
return (
|
|
78
|
+
self.category
|
|
79
|
+
in {
|
|
80
|
+
IntentCategory.DESTRUCTIVE_DATA,
|
|
81
|
+
IntentCategory.DATA_EXFILTRATION,
|
|
82
|
+
IntentCategory.PRIVILEGE_ESCALATION,
|
|
83
|
+
IntentCategory.SYSTEM_MODIFICATION,
|
|
84
|
+
IntentCategory.CODE_EXECUTION,
|
|
85
|
+
}
|
|
86
|
+
and self.confidence >= 0.5
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
# =============================================================================
|
|
91
|
+
# Policy Denied Exception
|
|
92
|
+
# =============================================================================
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class PolicyDenied(Exception):
|
|
96
|
+
"""Raised when an action is denied by semantic policy."""
|
|
97
|
+
|
|
98
|
+
def __init__(self, classification: IntentClassification, policy_name: str = ""):
|
|
99
|
+
self.classification = classification
|
|
100
|
+
self.policy_name = policy_name
|
|
101
|
+
super().__init__(
|
|
102
|
+
f"Denied by {policy_name or 'semantic policy'}: "
|
|
103
|
+
f"intent={classification.category.value} "
|
|
104
|
+
f"confidence={classification.confidence:.0%} "
|
|
105
|
+
f"signals={classification.matched_signals}"
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
# =============================================================================
|
|
110
|
+
# Signal Definitions
|
|
111
|
+
# =============================================================================
|
|
112
|
+
|
|
113
|
+
# Each signal: (pattern_regex, weight, explanation)
|
|
114
|
+
_SIGNALS: dict[IntentCategory, list[tuple]] = {
|
|
115
|
+
IntentCategory.DESTRUCTIVE_DATA: [
|
|
116
|
+
(r"\bDROP\s+(TABLE|DATABASE|INDEX|VIEW|SCHEMA)\b", 0.9, "SQL DROP statement"),
|
|
117
|
+
(r"\bTRUNCATE\s+TABLE\b", 0.9, "SQL TRUNCATE"),
|
|
118
|
+
(r"\bDELETE\s+FROM\b.*\bWHERE\s+1\s*=\s*1\b", 0.95, "DELETE all rows"),
|
|
119
|
+
(r"\bDELETE\s+FROM\b(?!.*\bWHERE\b)", 0.85, "DELETE without WHERE"),
|
|
120
|
+
(r"\bDELETE\s+FROM\b", 0.4, "DELETE with filter"),
|
|
121
|
+
(r"\b(wipe|purge|destroy|erase|nuke)\b", 0.7, "destructive verb"),
|
|
122
|
+
(r"\bremove\s+(all|every|entire)\b", 0.75, "remove-all pattern"),
|
|
123
|
+
(r"\bformat\s+(disk|drive|partition)\b", 0.9, "disk format"),
|
|
124
|
+
(r"\bALTER\s+TABLE\b.*\bDROP\b", 0.8, "ALTER TABLE DROP column"),
|
|
125
|
+
],
|
|
126
|
+
IntentCategory.DATA_EXFILTRATION: [
|
|
127
|
+
(r"\bSELECT\s+\*\s+FROM\b.*\bINTO\s+OUTFILE\b", 0.9, "SQL dump to file"),
|
|
128
|
+
(r"\bCOPY\s+.*\bTO\s+STDOUT\b", 0.8, "Postgres COPY to stdout"),
|
|
129
|
+
(r"\b(dump|export|backup)\s+(all|entire|full|complete)\b", 0.75, "full data export"),
|
|
130
|
+
(r"\b(upload|send|transmit)\s+.*\b(external|remote|s3|bucket)\b", 0.8, "external transfer"),
|
|
131
|
+
(r"\bpg_dump\b", 0.7, "database dump tool"),
|
|
132
|
+
(r"\bmysqldump\b", 0.7, "MySQL dump tool"),
|
|
133
|
+
(r"\b(wget|curl)\s+.*\|\s*", 0.6, "piped download"),
|
|
134
|
+
],
|
|
135
|
+
IntentCategory.PRIVILEGE_ESCALATION: [
|
|
136
|
+
(r"\bGRANT\s+(ALL|SUPERUSER|ADMIN)\b", 0.9, "SQL GRANT elevated"),
|
|
137
|
+
(r"\bGRANT\b", 0.4, "SQL GRANT"),
|
|
138
|
+
(r"\bsudo\b", 0.7, "sudo invocation"),
|
|
139
|
+
(r"\bchmod\s+777\b", 0.8, "world-writable permissions"),
|
|
140
|
+
(r"\bchmod\s+[0-7]*[67][0-7]{2}\b", 0.5, "permissive chmod"),
|
|
141
|
+
(r"\b(escalat|elevat)\w*\s*(privilege|permission|access)\b", 0.8, "escalation language"),
|
|
142
|
+
(r"\bALTER\s+USER\b.*\bSUPERUSER\b", 0.9, "make superuser"),
|
|
143
|
+
(r"\bsu\s+-\b", 0.7, "switch user root"),
|
|
144
|
+
(r"\bpasswd\b", 0.5, "password change"),
|
|
145
|
+
],
|
|
146
|
+
IntentCategory.SYSTEM_MODIFICATION: [
|
|
147
|
+
(r"\brm\s+-rf\b", 0.95, "recursive force delete"),
|
|
148
|
+
(r"\brm\s+-r\b", 0.7, "recursive delete"),
|
|
149
|
+
(r"\b(shutdown|reboot|halt|poweroff)\b", 0.8, "system power"),
|
|
150
|
+
(r"\bkill\s+-9\b", 0.7, "force kill process"),
|
|
151
|
+
(r"\bsystemctl\s+(stop|disable|mask)\b", 0.7, "stop system service"),
|
|
152
|
+
(r"\biptables\s+.*\bDROP\b", 0.8, "firewall drop rule"),
|
|
153
|
+
(r"\bregistry\s*(delete|modify)\b", 0.7, "Windows registry modification"),
|
|
154
|
+
(r"\bformat\s+[A-Z]:\b", 0.9, "format drive"),
|
|
155
|
+
],
|
|
156
|
+
IntentCategory.CODE_EXECUTION: [
|
|
157
|
+
(r"\b(exec|eval)\s*\(", 0.8, "dynamic code execution"),
|
|
158
|
+
(r"\bsubprocess\b", 0.5, "subprocess call"),
|
|
159
|
+
(r"\bos\.system\b", 0.7, "os.system call"),
|
|
160
|
+
(r"\b__import__\b", 0.7, "dynamic import"),
|
|
161
|
+
(r"\bcompile\s*\(", 0.5, "compile code"),
|
|
162
|
+
(r"\bpickle\.loads\b", 0.7, "unsafe deserialization"),
|
|
163
|
+
],
|
|
164
|
+
IntentCategory.NETWORK_ACCESS: [
|
|
165
|
+
(r"\b(fetch|requests\.get|requests\.post|urllib)\b", 0.4, "HTTP request"),
|
|
166
|
+
(r"\b(curl|wget)\s+http", 0.5, "command-line HTTP"),
|
|
167
|
+
(r"\bsocket\.connect\b", 0.6, "raw socket connection"),
|
|
168
|
+
(r"\bsmtplib\b", 0.5, "SMTP email"),
|
|
169
|
+
],
|
|
170
|
+
IntentCategory.DATA_READ: [
|
|
171
|
+
(r"\bSELECT\b(?!.*\bINTO\b)", 0.6, "SQL SELECT"),
|
|
172
|
+
(r"\b(read|get|fetch|list|show|describe)\b", 0.3, "read verb"),
|
|
173
|
+
],
|
|
174
|
+
IntentCategory.DATA_WRITE: [
|
|
175
|
+
(r"\b(INSERT|UPDATE)\b", 0.5, "SQL write"),
|
|
176
|
+
(r"\b(write|create|put|post|append)\b", 0.3, "write verb"),
|
|
177
|
+
],
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
# =============================================================================
|
|
182
|
+
# Externalised configuration dataclass
|
|
183
|
+
# =============================================================================
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
@dataclass
|
|
187
|
+
class SemanticPolicyConfig:
|
|
188
|
+
"""Structured configuration for semantic policy signals, loadable from YAML.
|
|
189
|
+
|
|
190
|
+
Attributes:
|
|
191
|
+
signals: Mapping of IntentCategory names to lists of
|
|
192
|
+
``(pattern, weight, explanation)`` tuples.
|
|
193
|
+
disclaimer: Disclaimer text shown in logs.
|
|
194
|
+
"""
|
|
195
|
+
|
|
196
|
+
signals: dict[str, list[tuple[str, float, str]]] = field(
|
|
197
|
+
default_factory=lambda: {
|
|
198
|
+
cat.value: [(p, w, e) for p, w, e in sigs]
|
|
199
|
+
for cat, sigs in _SIGNALS.items()
|
|
200
|
+
}
|
|
201
|
+
)
|
|
202
|
+
disclaimer: str = ""
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def load_semantic_policy_config(path: str) -> SemanticPolicyConfig:
|
|
206
|
+
"""Load semantic policy configuration from a YAML file.
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
path: Path to a YAML file with a ``signals`` section.
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
SemanticPolicyConfig populated from the YAML data.
|
|
213
|
+
|
|
214
|
+
Raises:
|
|
215
|
+
FileNotFoundError: If the config file does not exist.
|
|
216
|
+
ValueError: If the YAML is missing the ``signals`` section.
|
|
217
|
+
"""
|
|
218
|
+
import yaml
|
|
219
|
+
|
|
220
|
+
if not os.path.exists(path):
|
|
221
|
+
raise FileNotFoundError(f"Semantic policy config not found: {path}")
|
|
222
|
+
|
|
223
|
+
with open(path, "r", encoding="utf-8") as fh:
|
|
224
|
+
data = yaml.safe_load(fh.read())
|
|
225
|
+
|
|
226
|
+
if not isinstance(data, dict) or "signals" not in data:
|
|
227
|
+
raise ValueError(f"YAML file must contain a 'signals' section: {path}")
|
|
228
|
+
|
|
229
|
+
raw_signals = data["signals"]
|
|
230
|
+
signals: dict[str, list[tuple[str, float, str]]] = {}
|
|
231
|
+
for category_name, entries in raw_signals.items():
|
|
232
|
+
signals[category_name] = [
|
|
233
|
+
(entry["pattern"], float(entry["weight"]), entry.get("explanation", ""))
|
|
234
|
+
for entry in entries
|
|
235
|
+
]
|
|
236
|
+
|
|
237
|
+
return SemanticPolicyConfig(
|
|
238
|
+
signals=signals,
|
|
239
|
+
disclaimer=data.get("disclaimer", ""),
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
# =============================================================================
|
|
244
|
+
# Semantic Policy Engine
|
|
245
|
+
# =============================================================================
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
class SemanticPolicyEngine:
|
|
249
|
+
"""
|
|
250
|
+
Intent-based policy enforcement engine.
|
|
251
|
+
|
|
252
|
+
Classifies action+params into semantic intent categories using
|
|
253
|
+
weighted keyword signals, then enforces deny/allow policies.
|
|
254
|
+
|
|
255
|
+
This is a zero-dependency heuristic classifier designed to run in <1ms.
|
|
256
|
+
The API is stable — swap in an ML classifier later without changing callers.
|
|
257
|
+
"""
|
|
258
|
+
|
|
259
|
+
def __init__(
|
|
260
|
+
self,
|
|
261
|
+
deny: list[IntentCategory] | None = None,
|
|
262
|
+
confidence_threshold: float = 0.5,
|
|
263
|
+
custom_signals: dict[IntentCategory, list[tuple]] | None = None,
|
|
264
|
+
config: SemanticPolicyConfig | None = None,
|
|
265
|
+
):
|
|
266
|
+
"""
|
|
267
|
+
Args:
|
|
268
|
+
deny: Intent categories to deny (default: all dangerous categories)
|
|
269
|
+
confidence_threshold: Minimum confidence to trigger deny (0.0-1.0)
|
|
270
|
+
custom_signals: Additional signal patterns to merge with defaults
|
|
271
|
+
config: Optional externalized configuration loaded via
|
|
272
|
+
``load_semantic_policy_config()``.
|
|
273
|
+
"""
|
|
274
|
+
if config is None and custom_signals is None:
|
|
275
|
+
warnings.warn(
|
|
276
|
+
"SemanticPolicyEngine() uses built-in sample rules that may not "
|
|
277
|
+
"cover all malicious intent patterns. For production use, load an "
|
|
278
|
+
"explicit config with load_semantic_policy_config(). "
|
|
279
|
+
"See examples/policies/semantic-policy.yaml for a sample configuration.",
|
|
280
|
+
stacklevel=2,
|
|
281
|
+
)
|
|
282
|
+
self.deny_categories: set[IntentCategory] = set(deny) if deny else {
|
|
283
|
+
IntentCategory.DESTRUCTIVE_DATA,
|
|
284
|
+
IntentCategory.DATA_EXFILTRATION,
|
|
285
|
+
IntentCategory.PRIVILEGE_ESCALATION,
|
|
286
|
+
IntentCategory.SYSTEM_MODIFICATION,
|
|
287
|
+
IntentCategory.CODE_EXECUTION,
|
|
288
|
+
}
|
|
289
|
+
self.confidence_threshold = confidence_threshold
|
|
290
|
+
|
|
291
|
+
# Build signals from config or defaults
|
|
292
|
+
if config is not None:
|
|
293
|
+
self.signals: dict[IntentCategory, list[tuple]] = {}
|
|
294
|
+
for cat_name, sigs in config.signals.items():
|
|
295
|
+
try:
|
|
296
|
+
cat = IntentCategory(cat_name)
|
|
297
|
+
except ValueError:
|
|
298
|
+
continue
|
|
299
|
+
self.signals[cat] = list(sigs)
|
|
300
|
+
else:
|
|
301
|
+
self.signals = {k: list(v) for k, v in _SIGNALS.items()}
|
|
302
|
+
|
|
303
|
+
if custom_signals:
|
|
304
|
+
for cat, sigs in custom_signals.items():
|
|
305
|
+
self.signals.setdefault(cat, []).extend(sigs)
|
|
306
|
+
# Pre-compile regexes for performance
|
|
307
|
+
self._compiled: dict[IntentCategory, list[tuple]] = {}
|
|
308
|
+
for cat, sigs in self.signals.items():
|
|
309
|
+
self._compiled[cat] = [
|
|
310
|
+
(re.compile(pattern, re.IGNORECASE), weight, explanation)
|
|
311
|
+
for pattern, weight, explanation in sigs
|
|
312
|
+
]
|
|
313
|
+
|
|
314
|
+
def classify(
|
|
315
|
+
self, action: str, params: dict[str, Any]
|
|
316
|
+
) -> IntentClassification:
|
|
317
|
+
"""
|
|
318
|
+
Classify the semantic intent of an action+params.
|
|
319
|
+
|
|
320
|
+
Args:
|
|
321
|
+
action: Action name (e.g. "database_query")
|
|
322
|
+
params: Action parameters (e.g. {"query": "DROP TABLE users"})
|
|
323
|
+
|
|
324
|
+
Returns:
|
|
325
|
+
IntentClassification with category, confidence, and matched signals
|
|
326
|
+
"""
|
|
327
|
+
# Build the text corpus to scan
|
|
328
|
+
text = self._build_text(action, params)
|
|
329
|
+
|
|
330
|
+
best_category = IntentCategory.BENIGN
|
|
331
|
+
best_confidence = 0.0
|
|
332
|
+
best_signals: list = []
|
|
333
|
+
|
|
334
|
+
for category, compiled_sigs in self._compiled.items():
|
|
335
|
+
matched = []
|
|
336
|
+
total_weight = 0.0
|
|
337
|
+
|
|
338
|
+
for regex, weight, explanation in compiled_sigs:
|
|
339
|
+
if regex.search(text):
|
|
340
|
+
matched.append(explanation)
|
|
341
|
+
total_weight = max(total_weight, weight)
|
|
342
|
+
|
|
343
|
+
if matched and total_weight > best_confidence:
|
|
344
|
+
best_category = category
|
|
345
|
+
best_confidence = total_weight
|
|
346
|
+
best_signals = matched
|
|
347
|
+
|
|
348
|
+
return IntentClassification(
|
|
349
|
+
category=best_category,
|
|
350
|
+
confidence=round(best_confidence, 3),
|
|
351
|
+
matched_signals=tuple(best_signals),
|
|
352
|
+
explanation=(
|
|
353
|
+
f"Detected {best_category.value} intent "
|
|
354
|
+
f"({best_confidence:.0%} confidence) "
|
|
355
|
+
f"from {len(best_signals)} signal(s)"
|
|
356
|
+
if best_signals
|
|
357
|
+
else "No risk signals detected"
|
|
358
|
+
),
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
def check(
|
|
362
|
+
self,
|
|
363
|
+
action: str,
|
|
364
|
+
params: dict[str, Any],
|
|
365
|
+
*,
|
|
366
|
+
deny: list[IntentCategory] | None = None,
|
|
367
|
+
policy_name: str = "",
|
|
368
|
+
) -> IntentClassification:
|
|
369
|
+
"""
|
|
370
|
+
Classify and enforce — raises PolicyDenied if intent is denied.
|
|
371
|
+
|
|
372
|
+
Args:
|
|
373
|
+
action: Action name
|
|
374
|
+
params: Action parameters
|
|
375
|
+
deny: Override deny categories (uses engine defaults if None)
|
|
376
|
+
policy_name: Name for error messages
|
|
377
|
+
|
|
378
|
+
Returns:
|
|
379
|
+
IntentClassification if allowed
|
|
380
|
+
|
|
381
|
+
Raises:
|
|
382
|
+
PolicyDenied: If classified intent is in deny set above threshold
|
|
383
|
+
"""
|
|
384
|
+
classification = self.classify(action, params)
|
|
385
|
+
deny_set = set(deny) if deny else self.deny_categories
|
|
386
|
+
|
|
387
|
+
if (
|
|
388
|
+
classification.category in deny_set
|
|
389
|
+
and classification.confidence >= self.confidence_threshold
|
|
390
|
+
):
|
|
391
|
+
raise PolicyDenied(classification, policy_name)
|
|
392
|
+
|
|
393
|
+
return classification
|
|
394
|
+
|
|
395
|
+
@staticmethod
|
|
396
|
+
def _build_text(action: str, params: dict[str, Any]) -> str:
|
|
397
|
+
"""Flatten action + params into a single searchable string."""
|
|
398
|
+
parts = [action]
|
|
399
|
+
for value in params.values():
|
|
400
|
+
if isinstance(value, str):
|
|
401
|
+
parts.append(value)
|
|
402
|
+
elif isinstance(value, (list, tuple)):
|
|
403
|
+
parts.extend(str(v) for v in value)
|
|
404
|
+
elif isinstance(value, dict):
|
|
405
|
+
parts.extend(str(v) for v in value.values())
|
|
406
|
+
else:
|
|
407
|
+
parts.append(str(value))
|
|
408
|
+
return " ".join(parts)
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
# =============================================================================
|
|
412
|
+
# Public API
|
|
413
|
+
# =============================================================================
|
|
414
|
+
|
|
415
|
+
__all__ = [
|
|
416
|
+
"IntentCategory",
|
|
417
|
+
"IntentClassification",
|
|
418
|
+
"PolicyDenied",
|
|
419
|
+
"SemanticPolicyConfig",
|
|
420
|
+
"SemanticPolicyEngine",
|
|
421
|
+
"load_semantic_policy_config",
|
|
422
|
+
]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""Agent OS Governance API Server.
|
|
4
|
+
|
|
5
|
+
Provides a REST API for governance operations, enabling language-agnostic
|
|
6
|
+
access to Agent OS capabilities.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
from agent_os.server.app import GovServer, create_app
|
|
11
|
+
except ImportError: # pragma: no cover
|
|
12
|
+
GovServer = None # type: ignore[assignment,misc]
|
|
13
|
+
create_app = None # type: ignore[assignment]
|
|
14
|
+
|
|
15
|
+
__all__ = ["create_app", "GovServer"]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""Run Agent OS Governance API server."""
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import os
|
|
7
|
+
|
|
8
|
+
import uvicorn
|
|
9
|
+
|
|
10
|
+
from agent_os.server.app import GovServer
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def main() -> None:
|
|
14
|
+
parser = argparse.ArgumentParser(description="Agent OS Governance API server")
|
|
15
|
+
parser.add_argument("--host", default=os.environ.get("HOST", "127.0.0.1"))
|
|
16
|
+
parser.add_argument("--port", type=int, default=int(os.environ.get("PORT", "8080")))
|
|
17
|
+
parser.add_argument("--log-level", default=os.environ.get("LOG_LEVEL", "info"))
|
|
18
|
+
args = parser.parse_args()
|
|
19
|
+
|
|
20
|
+
server = GovServer()
|
|
21
|
+
uvicorn.run(server.app, host=args.host, port=args.port, log_level=args.log_level)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
if __name__ == "__main__":
|
|
25
|
+
main()
|