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
atr/access.py
ADDED
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""
|
|
4
|
+
Access control for ATR tools.
|
|
5
|
+
|
|
6
|
+
Provides permission-based access control for tool execution.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import threading
|
|
12
|
+
from dataclasses import dataclass, field
|
|
13
|
+
from enum import Enum
|
|
14
|
+
from typing import Any, Callable, Dict, FrozenSet, List, Optional, Set
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Permission(str, Enum):
|
|
18
|
+
"""Built-in permission types."""
|
|
19
|
+
|
|
20
|
+
READ = "read"
|
|
21
|
+
WRITE = "write"
|
|
22
|
+
EXECUTE = "execute"
|
|
23
|
+
ADMIN = "admin"
|
|
24
|
+
ALL = "*"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass(frozen=True)
|
|
28
|
+
class Principal:
|
|
29
|
+
"""Represents an entity (user, agent, service) that can access tools.
|
|
30
|
+
|
|
31
|
+
Attributes:
|
|
32
|
+
id: Unique identifier for the principal.
|
|
33
|
+
type: Type of principal (e.g., "agent", "user", "service").
|
|
34
|
+
roles: Set of roles assigned to this principal.
|
|
35
|
+
attributes: Additional attributes for attribute-based access control.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
id: str
|
|
39
|
+
type: str = "agent"
|
|
40
|
+
roles: FrozenSet[str] = field(default_factory=frozenset)
|
|
41
|
+
attributes: FrozenSet[tuple] = field(default_factory=frozenset)
|
|
42
|
+
|
|
43
|
+
def has_role(self, role: str) -> bool:
|
|
44
|
+
"""Check if principal has a specific role."""
|
|
45
|
+
return role in self.roles or "admin" in self.roles
|
|
46
|
+
|
|
47
|
+
def get_attribute(self, key: str) -> Optional[Any]:
|
|
48
|
+
"""Get an attribute value."""
|
|
49
|
+
for k, v in self.attributes:
|
|
50
|
+
if k == key:
|
|
51
|
+
return v
|
|
52
|
+
return None
|
|
53
|
+
|
|
54
|
+
@classmethod
|
|
55
|
+
def create(
|
|
56
|
+
cls,
|
|
57
|
+
id: str,
|
|
58
|
+
type: str = "agent",
|
|
59
|
+
roles: Optional[List[str]] = None,
|
|
60
|
+
attributes: Optional[Dict[str, Any]] = None,
|
|
61
|
+
) -> "Principal":
|
|
62
|
+
"""Create a principal with mutable inputs."""
|
|
63
|
+
return cls(
|
|
64
|
+
id=id,
|
|
65
|
+
type=type,
|
|
66
|
+
roles=frozenset(roles or []),
|
|
67
|
+
attributes=frozenset((attributes or {}).items()),
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@dataclass
|
|
72
|
+
class AccessPolicy:
|
|
73
|
+
"""Defines access requirements for a tool.
|
|
74
|
+
|
|
75
|
+
Attributes:
|
|
76
|
+
allowed_principals: Specific principal IDs that can access.
|
|
77
|
+
allowed_roles: Roles that can access.
|
|
78
|
+
allowed_types: Principal types that can access.
|
|
79
|
+
denied_principals: Principals explicitly denied.
|
|
80
|
+
required_attributes: Attributes that must match.
|
|
81
|
+
custom_check: Custom authorization function.
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
allowed_principals: Set[str] = field(default_factory=set)
|
|
85
|
+
allowed_roles: Set[str] = field(default_factory=set)
|
|
86
|
+
allowed_types: Set[str] = field(default_factory=set)
|
|
87
|
+
denied_principals: Set[str] = field(default_factory=set)
|
|
88
|
+
required_attributes: Dict[str, Any] = field(default_factory=dict)
|
|
89
|
+
custom_check: Optional[Callable[[Principal, str], bool]] = None
|
|
90
|
+
|
|
91
|
+
def allows(self, principal: Principal, tool_name: str) -> bool:
|
|
92
|
+
"""Check if the policy allows access.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
principal: The principal requesting access.
|
|
96
|
+
tool_name: Name of the tool being accessed.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
True if access is allowed, False otherwise.
|
|
100
|
+
"""
|
|
101
|
+
# Explicit deny takes precedence
|
|
102
|
+
if principal.id in self.denied_principals:
|
|
103
|
+
return False
|
|
104
|
+
|
|
105
|
+
# Check custom authorization
|
|
106
|
+
if self.custom_check is not None:
|
|
107
|
+
return self.custom_check(principal, tool_name)
|
|
108
|
+
|
|
109
|
+
# Admin role bypasses all checks
|
|
110
|
+
if principal.has_role("admin"):
|
|
111
|
+
return True
|
|
112
|
+
|
|
113
|
+
# Check explicit principal allowlist
|
|
114
|
+
if self.allowed_principals and principal.id in self.allowed_principals:
|
|
115
|
+
return True
|
|
116
|
+
|
|
117
|
+
# Check role-based access
|
|
118
|
+
if self.allowed_roles and any(principal.has_role(role) for role in self.allowed_roles):
|
|
119
|
+
return True
|
|
120
|
+
|
|
121
|
+
# Check type-based access
|
|
122
|
+
if self.allowed_types and principal.type in self.allowed_types:
|
|
123
|
+
return True
|
|
124
|
+
|
|
125
|
+
# Check required attributes
|
|
126
|
+
if self.required_attributes:
|
|
127
|
+
for key, required_value in self.required_attributes.items():
|
|
128
|
+
actual_value = principal.get_attribute(key)
|
|
129
|
+
if actual_value != required_value:
|
|
130
|
+
return False
|
|
131
|
+
return True
|
|
132
|
+
|
|
133
|
+
# If no restrictions defined, allow by default
|
|
134
|
+
if (
|
|
135
|
+
not self.allowed_principals
|
|
136
|
+
and not self.allowed_roles
|
|
137
|
+
and not self.allowed_types
|
|
138
|
+
and not self.required_attributes
|
|
139
|
+
):
|
|
140
|
+
return True
|
|
141
|
+
|
|
142
|
+
return False
|
|
143
|
+
|
|
144
|
+
@classmethod
|
|
145
|
+
def allow_all(cls) -> "AccessPolicy":
|
|
146
|
+
"""Create a policy that allows all access."""
|
|
147
|
+
return cls()
|
|
148
|
+
|
|
149
|
+
@classmethod
|
|
150
|
+
def deny_all(cls) -> "AccessPolicy":
|
|
151
|
+
"""Create a policy that denies all access."""
|
|
152
|
+
return cls(custom_check=lambda _p, _t: False)
|
|
153
|
+
|
|
154
|
+
@classmethod
|
|
155
|
+
def roles_only(cls, *roles: str) -> "AccessPolicy":
|
|
156
|
+
"""Create a policy that only allows specific roles."""
|
|
157
|
+
return cls(allowed_roles=set(roles))
|
|
158
|
+
|
|
159
|
+
@classmethod
|
|
160
|
+
def principals_only(cls, *principals: str) -> "AccessPolicy":
|
|
161
|
+
"""Create a policy that only allows specific principals."""
|
|
162
|
+
return cls(allowed_principals=set(principals))
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
class AccessDeniedError(Exception):
|
|
166
|
+
"""Raised when access to a tool is denied."""
|
|
167
|
+
|
|
168
|
+
def __init__(self, principal: Principal, tool_name: str, reason: str = ""):
|
|
169
|
+
self.principal = principal
|
|
170
|
+
self.tool_name = tool_name
|
|
171
|
+
self.reason = reason
|
|
172
|
+
message = f"Access denied for '{principal.id}' to tool '{tool_name}'"
|
|
173
|
+
if reason:
|
|
174
|
+
message += f": {reason}"
|
|
175
|
+
super().__init__(message)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class AccessControlManager:
|
|
179
|
+
"""Manages access control for tools.
|
|
180
|
+
|
|
181
|
+
Example:
|
|
182
|
+
>>> manager = AccessControlManager()
|
|
183
|
+
>>>
|
|
184
|
+
>>> # Set policy for a tool
|
|
185
|
+
>>> manager.set_policy("sensitive_tool", AccessPolicy.roles_only("admin", "security"))
|
|
186
|
+
>>>
|
|
187
|
+
>>> # Check access
|
|
188
|
+
>>> agent = Principal.create("agent-1", roles=["claims"])
|
|
189
|
+
>>> if manager.can_access(agent, "sensitive_tool"):
|
|
190
|
+
... # Execute tool
|
|
191
|
+
... pass
|
|
192
|
+
"""
|
|
193
|
+
|
|
194
|
+
def __init__(self, default_policy: Optional[AccessPolicy] = None):
|
|
195
|
+
"""Initialize access control manager.
|
|
196
|
+
|
|
197
|
+
Args:
|
|
198
|
+
default_policy: Policy to use when no specific policy is set.
|
|
199
|
+
"""
|
|
200
|
+
self._policies: Dict[str, AccessPolicy] = {}
|
|
201
|
+
self._default_policy = default_policy or AccessPolicy.allow_all()
|
|
202
|
+
self._lock = threading.RLock()
|
|
203
|
+
self._audit_log: List[Dict[str, Any]] = []
|
|
204
|
+
self._audit_enabled = False
|
|
205
|
+
|
|
206
|
+
def set_policy(self, tool_name: str, policy: AccessPolicy) -> None:
|
|
207
|
+
"""Set access policy for a tool.
|
|
208
|
+
|
|
209
|
+
Args:
|
|
210
|
+
tool_name: Name of the tool.
|
|
211
|
+
policy: The access policy to apply.
|
|
212
|
+
"""
|
|
213
|
+
with self._lock:
|
|
214
|
+
self._policies[tool_name] = policy
|
|
215
|
+
|
|
216
|
+
def get_policy(self, tool_name: str) -> AccessPolicy:
|
|
217
|
+
"""Get access policy for a tool.
|
|
218
|
+
|
|
219
|
+
Args:
|
|
220
|
+
tool_name: Name of the tool.
|
|
221
|
+
|
|
222
|
+
Returns:
|
|
223
|
+
The tool's policy or default policy.
|
|
224
|
+
"""
|
|
225
|
+
with self._lock:
|
|
226
|
+
return self._policies.get(tool_name, self._default_policy)
|
|
227
|
+
|
|
228
|
+
def remove_policy(self, tool_name: str) -> bool:
|
|
229
|
+
"""Remove a tool's specific policy.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
tool_name: Name of the tool.
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
True if policy was removed, False if didn't exist.
|
|
236
|
+
"""
|
|
237
|
+
with self._lock:
|
|
238
|
+
if tool_name in self._policies:
|
|
239
|
+
del self._policies[tool_name]
|
|
240
|
+
return True
|
|
241
|
+
return False
|
|
242
|
+
|
|
243
|
+
def can_access(self, principal: Principal, tool_name: str) -> bool:
|
|
244
|
+
"""Check if a principal can access a tool.
|
|
245
|
+
|
|
246
|
+
Args:
|
|
247
|
+
principal: The principal requesting access.
|
|
248
|
+
tool_name: Name of the tool.
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
True if access is allowed.
|
|
252
|
+
"""
|
|
253
|
+
policy = self.get_policy(tool_name)
|
|
254
|
+
allowed = policy.allows(principal, tool_name)
|
|
255
|
+
|
|
256
|
+
if self._audit_enabled:
|
|
257
|
+
self._log_access(principal, tool_name, allowed)
|
|
258
|
+
|
|
259
|
+
return allowed
|
|
260
|
+
|
|
261
|
+
def require_access(self, principal: Principal, tool_name: str) -> None:
|
|
262
|
+
"""Require access or raise AccessDeniedError.
|
|
263
|
+
|
|
264
|
+
Args:
|
|
265
|
+
principal: The principal requesting access.
|
|
266
|
+
tool_name: Name of the tool.
|
|
267
|
+
|
|
268
|
+
Raises:
|
|
269
|
+
AccessDeniedError: If access is denied.
|
|
270
|
+
"""
|
|
271
|
+
if not self.can_access(principal, tool_name):
|
|
272
|
+
raise AccessDeniedError(principal, tool_name)
|
|
273
|
+
|
|
274
|
+
def enable_audit(self, enabled: bool = True) -> None:
|
|
275
|
+
"""Enable or disable audit logging.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
enabled: Whether to enable audit logging.
|
|
279
|
+
"""
|
|
280
|
+
self._audit_enabled = enabled
|
|
281
|
+
|
|
282
|
+
def get_audit_log(self) -> List[Dict[str, Any]]:
|
|
283
|
+
"""Get the audit log.
|
|
284
|
+
|
|
285
|
+
Returns:
|
|
286
|
+
List of audit log entries.
|
|
287
|
+
"""
|
|
288
|
+
with self._lock:
|
|
289
|
+
return list(self._audit_log)
|
|
290
|
+
|
|
291
|
+
def clear_audit_log(self) -> None:
|
|
292
|
+
"""Clear the audit log."""
|
|
293
|
+
with self._lock:
|
|
294
|
+
self._audit_log.clear()
|
|
295
|
+
|
|
296
|
+
def _log_access(self, principal: Principal, tool_name: str, allowed: bool) -> None:
|
|
297
|
+
"""Log an access attempt."""
|
|
298
|
+
from datetime import datetime
|
|
299
|
+
|
|
300
|
+
with self._lock:
|
|
301
|
+
self._audit_log.append(
|
|
302
|
+
{
|
|
303
|
+
"timestamp": datetime.now().isoformat(),
|
|
304
|
+
"principal_id": principal.id,
|
|
305
|
+
"principal_type": principal.type,
|
|
306
|
+
"tool_name": tool_name,
|
|
307
|
+
"allowed": allowed,
|
|
308
|
+
}
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
# Keep only last 10000 entries
|
|
312
|
+
if len(self._audit_log) > 10000:
|
|
313
|
+
self._audit_log = self._audit_log[-10000:]
|
|
314
|
+
|
|
315
|
+
def list_accessible_tools(self, principal: Principal, tool_names: List[str]) -> List[str]:
|
|
316
|
+
"""Get list of tools a principal can access.
|
|
317
|
+
|
|
318
|
+
Args:
|
|
319
|
+
principal: The principal to check.
|
|
320
|
+
tool_names: List of tool names to check.
|
|
321
|
+
|
|
322
|
+
Returns:
|
|
323
|
+
List of accessible tool names.
|
|
324
|
+
"""
|
|
325
|
+
return [name for name in tool_names if self.can_access(principal, name)]
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
# Global access control manager
|
|
329
|
+
_global_access_manager: AccessControlManager = AccessControlManager()
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def get_access_manager() -> AccessControlManager:
|
|
333
|
+
"""Get the global access control manager.
|
|
334
|
+
|
|
335
|
+
Returns:
|
|
336
|
+
The global AccessControlManager instance.
|
|
337
|
+
"""
|
|
338
|
+
return _global_access_manager
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def set_access_manager(manager: AccessControlManager) -> None:
|
|
342
|
+
"""Set the global access control manager.
|
|
343
|
+
|
|
344
|
+
Args:
|
|
345
|
+
manager: The manager to use globally.
|
|
346
|
+
"""
|
|
347
|
+
global _global_access_manager
|
|
348
|
+
_global_access_manager = manager
|