agenticdome-python-sdk 1.1.2__py3-none-any.whl → 1.1.4__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.
- {agenticdome_python_sdk-1.1.2.dist-info → agenticdome_python_sdk-1.1.4.dist-info}/METADATA +89 -52
- agenticdome_python_sdk-1.1.4.dist-info/RECORD +21 -0
- {agenticdome_python_sdk-1.1.2.dist-info → agenticdome_python_sdk-1.1.4.dist-info}/WHEEL +1 -1
- agenticdome_sdk/__init__.py +8 -0
- agenticdome_sdk/client.py +153 -9
- agenticdome_sdk/identity.py +129 -0
- agenticdome_sdk/langgraph.py +34 -0
- agenticdome_sdk/microsoft_agent_framework.py +3 -0
- agenticdome_sdk/microsoft_ai_foundry.py +1 -0
- agenticdome_sdk/proof.py +80 -0
- agenticdome_python_sdk-1.1.2.dist-info/RECORD +0 -19
- {agenticdome_python_sdk-1.1.2.dist-info → agenticdome_python_sdk-1.1.4.dist-info}/licenses/LICENSE +0 -0
- {agenticdome_python_sdk-1.1.2.dist-info → agenticdome_python_sdk-1.1.4.dist-info}/top_level.txt +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agenticdome-python-sdk
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.4
|
|
4
4
|
Summary: Official Python SDK for AgenticDome security guardrails, DLP, tool authorization, and multi-agent delegation enforcement.
|
|
5
5
|
Author: AgenticDome
|
|
6
6
|
License: Proprietary
|
|
7
|
-
Project-URL: Homepage, https://
|
|
7
|
+
Project-URL: Homepage, https://www.agenticdome.io
|
|
8
8
|
Project-URL: Repository, https://github.com/agenticdome/agenticdome-python-sdk
|
|
9
9
|
Project-URL: Documentation, https://github.com/agenticdome/agenticdome-python-sdk#readme
|
|
10
10
|
Project-URL: Issues, https://github.com/agenticdome/agenticdome-python-sdk/issues
|
|
@@ -27,56 +27,59 @@ License-File: LICENSE
|
|
|
27
27
|
Requires-Dist: requests>=2.31.0
|
|
28
28
|
Requires-Dist: urllib3>=2.0.0
|
|
29
29
|
Provides-Extra: crewai
|
|
30
|
-
Requires-Dist: crewai; extra == "crewai"
|
|
30
|
+
Requires-Dist: crewai==1.15.5; extra == "crewai"
|
|
31
31
|
Provides-Extra: redis
|
|
32
32
|
Requires-Dist: redis>=4.5.0; extra == "redis"
|
|
33
|
+
Provides-Extra: pop
|
|
34
|
+
Requires-Dist: cryptography>=42.0.0; extra == "pop"
|
|
33
35
|
Provides-Extra: pydanticai
|
|
34
|
-
Requires-Dist: pydantic-ai; extra == "pydanticai"
|
|
36
|
+
Requires-Dist: pydantic-ai==2.14.1; extra == "pydanticai"
|
|
35
37
|
Requires-Dist: anyio>=4.0.0; extra == "pydanticai"
|
|
36
38
|
Provides-Extra: pydantic
|
|
37
|
-
Requires-Dist: pydantic-ai; extra == "pydantic"
|
|
39
|
+
Requires-Dist: pydantic-ai==2.14.1; extra == "pydantic"
|
|
38
40
|
Requires-Dist: anyio>=4.0.0; extra == "pydantic"
|
|
39
41
|
Provides-Extra: langgraph
|
|
40
|
-
Requires-Dist: langgraph; extra == "langgraph"
|
|
41
|
-
Requires-Dist: langchain-core; extra == "langgraph"
|
|
42
|
+
Requires-Dist: langgraph==1.2.9; extra == "langgraph"
|
|
43
|
+
Requires-Dist: langchain-core==1.5.0; extra == "langgraph"
|
|
42
44
|
Requires-Dist: anyio>=4.0.0; extra == "langgraph"
|
|
43
45
|
Provides-Extra: microsoft
|
|
44
46
|
Provides-Extra: foundry
|
|
45
|
-
Requires-Dist: azure-ai-projects; extra == "foundry"
|
|
46
|
-
Requires-Dist: azure-identity; extra == "foundry"
|
|
47
|
+
Requires-Dist: azure-ai-projects==2.3.0; extra == "foundry"
|
|
48
|
+
Requires-Dist: azure-identity==1.25.3; extra == "foundry"
|
|
47
49
|
Provides-Extra: agno
|
|
48
|
-
Requires-Dist: agno; extra == "agno"
|
|
50
|
+
Requires-Dist: agno==2.8.0; extra == "agno"
|
|
49
51
|
Provides-Extra: openai-agents
|
|
50
|
-
Requires-Dist: openai-agents; extra == "openai-agents"
|
|
52
|
+
Requires-Dist: openai-agents==0.18.3; extra == "openai-agents"
|
|
51
53
|
Provides-Extra: mcp
|
|
52
|
-
Requires-Dist: mcp; extra == "mcp"
|
|
54
|
+
Requires-Dist: mcp<=1.28.1,>=1.26.0; extra == "mcp"
|
|
53
55
|
Provides-Extra: bedrock
|
|
54
|
-
Requires-Dist: boto3; extra == "bedrock"
|
|
56
|
+
Requires-Dist: boto3==1.43.52; extra == "bedrock"
|
|
55
57
|
Provides-Extra: aws-bedrock
|
|
56
|
-
Requires-Dist: boto3; extra == "aws-bedrock"
|
|
58
|
+
Requires-Dist: boto3==1.43.52; extra == "aws-bedrock"
|
|
57
59
|
Provides-Extra: llamaindex
|
|
58
|
-
Requires-Dist: llama-index; extra == "llamaindex"
|
|
60
|
+
Requires-Dist: llama-index==0.14.23; extra == "llamaindex"
|
|
59
61
|
Provides-Extra: llama-index
|
|
60
|
-
Requires-Dist: llama-index; extra == "llama-index"
|
|
62
|
+
Requires-Dist: llama-index==0.14.23; extra == "llama-index"
|
|
61
63
|
Provides-Extra: google-adk
|
|
62
|
-
Requires-Dist: google-adk; extra == "google-adk"
|
|
64
|
+
Requires-Dist: google-adk==2.5.0; extra == "google-adk"
|
|
63
65
|
Provides-Extra: adk
|
|
64
|
-
Requires-Dist: google-adk; extra == "adk"
|
|
66
|
+
Requires-Dist: google-adk==2.5.0; extra == "adk"
|
|
65
67
|
Provides-Extra: all
|
|
66
|
-
Requires-Dist: crewai; extra == "all"
|
|
68
|
+
Requires-Dist: crewai==1.15.5; extra == "all"
|
|
67
69
|
Requires-Dist: redis>=4.5.0; extra == "all"
|
|
68
|
-
Requires-Dist:
|
|
70
|
+
Requires-Dist: cryptography>=42.0.0; extra == "all"
|
|
71
|
+
Requires-Dist: pydantic-ai==2.14.1; extra == "all"
|
|
69
72
|
Requires-Dist: anyio>=4.0.0; extra == "all"
|
|
70
|
-
Requires-Dist: langgraph; extra == "all"
|
|
71
|
-
Requires-Dist: langchain-core; extra == "all"
|
|
72
|
-
Requires-Dist: agno; extra == "all"
|
|
73
|
-
Requires-Dist: azure-ai-projects; extra == "all"
|
|
74
|
-
Requires-Dist: azure-identity; extra == "all"
|
|
75
|
-
Requires-Dist: openai-agents; extra == "all"
|
|
76
|
-
Requires-Dist: mcp; extra == "all"
|
|
77
|
-
Requires-Dist: boto3; extra == "all"
|
|
78
|
-
Requires-Dist: llama-index; extra == "all"
|
|
79
|
-
Requires-Dist: google-adk; extra == "all"
|
|
73
|
+
Requires-Dist: langgraph==1.2.9; extra == "all"
|
|
74
|
+
Requires-Dist: langchain-core==1.5.0; extra == "all"
|
|
75
|
+
Requires-Dist: agno==2.8.0; extra == "all"
|
|
76
|
+
Requires-Dist: azure-ai-projects==2.3.0; extra == "all"
|
|
77
|
+
Requires-Dist: azure-identity==1.25.3; extra == "all"
|
|
78
|
+
Requires-Dist: openai-agents==0.18.3; extra == "all"
|
|
79
|
+
Requires-Dist: mcp<=1.28.1,>=1.26.0; extra == "all"
|
|
80
|
+
Requires-Dist: boto3==1.43.52; extra == "all"
|
|
81
|
+
Requires-Dist: llama-index==0.14.23; extra == "all"
|
|
82
|
+
Requires-Dist: google-adk==2.5.0; extra == "all"
|
|
80
83
|
Provides-Extra: dev
|
|
81
84
|
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
82
85
|
Requires-Dist: ruff>=0.5.0; extra == "dev"
|
|
@@ -155,7 +158,7 @@ Your local Python runtime executes agents, tools, workflows, and framework-speci
|
|
|
155
158
|
[ LOCAL ENTERPRISE RUNTIME PERIMETER ] [ AGENTICDOME CENTRAL PLANE ]
|
|
156
159
|
|
|
157
160
|
+-------------------------------------------------+ +-----------------------------+
|
|
158
|
-
| Python Agent Runtime | | https://
|
|
161
|
+
| Python Agent Runtime | | https://demo-sidecar.agenticdome.io |
|
|
159
162
|
| CrewAI / PydanticAI / LangGraph / Microsoft AF / AI Foundry / Agno / OpenAI Agents / MCP Hosts / Bedrock / Google ADK / LlamaIndex | | Centralized Policy Engine |
|
|
160
163
|
+-------------------------------------------------+ +-----------------------------+
|
|
161
164
|
| | ^ ^
|
|
@@ -225,15 +228,48 @@ Authorizes tool calls before execution using:
|
|
|
225
228
|
|
|
226
229
|
AgenticDome can transparently authorize multi-agent delegation workflows and issue decision tokens that bind:
|
|
227
230
|
|
|
231
|
+
- Originating human subject, when present
|
|
232
|
+
- Ordered and nested agent actor chain
|
|
228
233
|
- Source manager agent
|
|
229
234
|
- Target specialist agent
|
|
230
235
|
- Tool name
|
|
231
236
|
- Tool arguments
|
|
232
237
|
- Session ID
|
|
238
|
+
- Trace and lineage root/parent IDs
|
|
239
|
+
- Intent digest, policy binding, authorized scopes, and trust epochs
|
|
233
240
|
- Tenant context
|
|
234
241
|
- Policy decision
|
|
235
242
|
|
|
236
|
-
|
|
243
|
+
Execution verification consumes the server-side call budget and checks revocation state. Optional proof-bound decisions use a DPoP-style signed JWT tied to the decision token hash; sending the public-key thumbprint alone is not treated as proof.
|
|
244
|
+
|
|
245
|
+
Install the proof helper extra and create a runtime-held key:
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
pip install "agenticdome-python-sdk[pop]"
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
```python
|
|
252
|
+
from agenticdome_sdk import create_dpop_proof, generate_rsa_proof_key
|
|
253
|
+
|
|
254
|
+
proof_key = generate_rsa_proof_key()
|
|
255
|
+
# Pass proof_key["thumbprint"] as proof_thumbprint when authorizing.
|
|
256
|
+
proof = create_dpop_proof(
|
|
257
|
+
proof_key["private_key_pem"],
|
|
258
|
+
access_token=decision_token,
|
|
259
|
+
method="POST",
|
|
260
|
+
uri="/a2a",
|
|
261
|
+
)
|
|
262
|
+
client.a2a_verify_decision_token_rpc(
|
|
263
|
+
decision_token,
|
|
264
|
+
tool_name=tool_name,
|
|
265
|
+
tool_args=tool_args,
|
|
266
|
+
agent_id=worker_id,
|
|
267
|
+
source_agent_id=manager_id,
|
|
268
|
+
proof_token=proof,
|
|
269
|
+
)
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
This helps prevent unauthorized lateral privilege escalation and stolen-token replay between agents.
|
|
237
273
|
|
|
238
274
|
### Inline Output Data Loss Prevention, DLP
|
|
239
275
|
|
|
@@ -302,6 +338,7 @@ Install the extra for the framework you use:
|
|
|
302
338
|
| AWS Bedrock / Bedrock Agents | `pip install "agenticdome-python-sdk[bedrock]"` |
|
|
303
339
|
| MCP host / gateway | `pip install "agenticdome-python-sdk[mcp]"` |
|
|
304
340
|
| Redis token storage | `pip install "agenticdome-python-sdk[redis]"` |
|
|
341
|
+
| Proof-of-possession helpers | `pip install "agenticdome-python-sdk[pop]"` |
|
|
305
342
|
| All optional integrations | `pip install "agenticdome-python-sdk[all]"` |
|
|
306
343
|
|
|
307
344
|
Some adapters are dependency-light at import time. Google ADK, LlamaIndex, Bedrock, MCP, and Microsoft helpers can wrap local boundaries without forcing one exact runtime stack; install the framework packages your application actually uses.
|
|
@@ -315,8 +352,8 @@ Set these environment variables in your local shell, container, CI/CD environmen
|
|
|
315
352
|
### Required Variables
|
|
316
353
|
|
|
317
354
|
```bash
|
|
318
|
-
#
|
|
319
|
-
export AGENTICDOME_API_BASE="https://
|
|
355
|
+
# Tenant runtime sidecar URL. Do not use the control-plane website URL here.
|
|
356
|
+
export AGENTICDOME_API_BASE="https://demo-sidecar.agenticdome.io"
|
|
320
357
|
|
|
321
358
|
# Secure access token generated in the AgenticDome console.
|
|
322
359
|
export AGENTICDOME_API_KEY="your_api_key_abc123..."
|
|
@@ -409,7 +446,7 @@ Set these values in the same place you configure your Python application runtime
|
|
|
409
446
|
Minimum production configuration:
|
|
410
447
|
|
|
411
448
|
```bash
|
|
412
|
-
export AGENTICDOME_API_BASE="https://
|
|
449
|
+
export AGENTICDOME_API_BASE="https://demo-sidecar.agenticdome.io"
|
|
413
450
|
export AGENTICDOME_API_KEY="your_api_key"
|
|
414
451
|
export AGENTICDOME_TENANT_ID="your_tenant_id"
|
|
415
452
|
export AGENTICDOME_FAIL_CLOSED="true"
|
|
@@ -569,7 +606,7 @@ secure_refund = firewall.wrap_delegated_tool_handler(
|
|
|
569
606
|
|
|
570
607
|
| Environment Variable | Type | Default | Description |
|
|
571
608
|
| :--- | :--- | :--- | :--- |
|
|
572
|
-
| `AGENTICDOME_API_BASE` | string | required |
|
|
609
|
+
| `AGENTICDOME_API_BASE` | string | required | Tenant runtime sidecar origin, for example `https://demo-sidecar.agenticdome.io`. This is separate from the control-plane console URL. |
|
|
573
610
|
| `AGENTICDOME_API_KEY` | string | required | API key generated in the AgenticDome console. |
|
|
574
611
|
| `AGENTICDOME_TENANT_ID` | string | required | Tenant or organization isolation namespace. |
|
|
575
612
|
| `AGENTICDOME_PLATFORM` | string | framework-specific | Runtime platform label included in policy context. |
|
|
@@ -777,7 +814,7 @@ Use the core client when you own the runtime loop or have a custom gateway. This
|
|
|
777
814
|
from agenticdome_sdk.client import AgentGuardClient
|
|
778
815
|
|
|
779
816
|
client = AgentGuardClient(
|
|
780
|
-
api_base="https://
|
|
817
|
+
api_base="https://demo-sidecar.agenticdome.io",
|
|
781
818
|
api_key="your-api-key",
|
|
782
819
|
tenant_id="your-tenant-id",
|
|
783
820
|
timeout=20,
|
|
@@ -1132,7 +1169,7 @@ pip install "agenticdome-python-sdk[pydanticai]"
|
|
|
1132
1169
|
[ PYDANTICAI AGENT RUNTIME PERIMETER ] [ AGENTICDOME CONTROL PLANE ]
|
|
1133
1170
|
|
|
1134
1171
|
+-------------------------------------------------+ +-----------------------------+
|
|
1135
|
-
| Agent.run() Execution Loop | | https://
|
|
1172
|
+
| Agent.run() Execution Loop | | https://demo-sidecar.agenticdome.io |
|
|
1136
1173
|
+-------------------------------------------------+ +-----------------------------+
|
|
1137
1174
|
| | ^ ^
|
|
1138
1175
|
| 1. before_runner_init | 4. after | Verdict / DLP |
|
|
@@ -1261,7 +1298,7 @@ PydanticAI lifecycle hook APIs have evolved. Current PydanticAI documents `pydan
|
|
|
1261
1298
|
- If compatible legacy lifecycle decorators are available, `attach_to_agent()` attaches prompt ingress and egress DLP hooks.
|
|
1262
1299
|
- If native `Hooks` capabilities are available, `create_hooks()` returns a capability object you can pass into `Agent(..., capabilities=[...])`.
|
|
1263
1300
|
- If lifecycle decorators are not available, `@firewall.secure_tool(...)` still protects tool execution.
|
|
1264
|
-
- In production mode, configure
|
|
1301
|
+
- In production mode, configure the tenant runtime sidecar, API key, tenant ID, and stable session IDs.
|
|
1265
1302
|
- `AGENTICDOME_BLOCK_ON_SENSITIVE_OUTPUT=true` means AgenticDome may ask Mesh to block sensitive output; the SDK only blocks when the policy response verdict is `BLOCKED`.
|
|
1266
1303
|
|
|
1267
1304
|
---
|
|
@@ -1297,7 +1334,7 @@ pip install "agenticdome-python-sdk[langgraph]"
|
|
|
1297
1334
|
[ LANGGRAPH STATEGRAPH RUNTIME ] [ AGENTICDOME CONTROL PLANE ]
|
|
1298
1335
|
|
|
1299
1336
|
+-----------------------------------------------+ +-----------------------------+
|
|
1300
|
-
| StateGraph / CompiledStateGraph | | https://
|
|
1337
|
+
| StateGraph / CompiledStateGraph | | https://demo-sidecar.agenticdome.io |
|
|
1301
1338
|
+-----------------------------------------------+ +-----------------------------+
|
|
1302
1339
|
| | ^ ^
|
|
1303
1340
|
| 1. user message | 2. tool calls | 4. verdict / token | validate
|
|
@@ -1512,7 +1549,7 @@ Install the Microsoft Agent Framework packages used by your application separate
|
|
|
1512
1549
|
[ MICROSOFT AGENT FRAMEWORK PYTHON RUNTIME ] [ AGENTICDOME CONTROL PLANE ]
|
|
1513
1550
|
|
|
1514
1551
|
+------------------------------------------------+ +-----------------------------+
|
|
1515
|
-
| Agent.run / Workflow.run / Function Tool | | https://
|
|
1552
|
+
| Agent.run / Workflow.run / Function Tool | | https://demo-sidecar.agenticdome.io |
|
|
1516
1553
|
+------------------------------------------------+ +-----------------------------+
|
|
1517
1554
|
| | ^ ^
|
|
1518
1555
|
| 1. input text | 2. tool args | verdict / token | validate
|
|
@@ -1709,7 +1746,7 @@ The Foundry integration supports:
|
|
|
1709
1746
|
- Direct tool-argument stripping, lightweight JSON-schema validation, and sanitized-argument execution when AgenticDome returns safer arguments
|
|
1710
1747
|
- Enterprise identity context propagation for Entra IDs, roles/scopes, Foundry project IDs, and Purview or sensitivity labels
|
|
1711
1748
|
- Production-mode stable session ID enforcement and output-sanitization requirements
|
|
1712
|
-
- Output DLP through Mesh using the required
|
|
1749
|
+
- Output DLP through Mesh using the required tenant runtime sidecar URL, API key, and tenant ID
|
|
1713
1750
|
- Structured-output preservation by parsing sanitized JSON back to dictionaries/lists where possible
|
|
1714
1751
|
- Local rate limits, input/output/tool-argument size limits, retries, circuit breaker behavior, audit logging, and OpenTelemetry span events
|
|
1715
1752
|
- Streaming response sanitization through `sanitize_streaming_response()`
|
|
@@ -1735,7 +1772,7 @@ If your application uses Microsoft Agent Framework hosted agents, install the Fo
|
|
|
1735
1772
|
Foundry threat-contract calls use bearer authentication:
|
|
1736
1773
|
|
|
1737
1774
|
```bash
|
|
1738
|
-
export AGENTICDOME_API_BASE="https://
|
|
1775
|
+
export AGENTICDOME_API_BASE="https://demo-sidecar.agenticdome.io"
|
|
1739
1776
|
export AGENTICDOME_BEARER_TOKEN="your_foundry_threat_contract_bearer_token"
|
|
1740
1777
|
```
|
|
1741
1778
|
|
|
@@ -1894,7 +1931,7 @@ from agenticdome_sdk.microsoft_ai_foundry import (
|
|
|
1894
1931
|
- Production deployments should pass a stable `session_id`, `run_id`, `trace_id`, `conversation_id`, or `thread_id`; generated fallback IDs are intended for local development only.
|
|
1895
1932
|
- Pass Entra identity, roles/scopes, Foundry project IDs, and Purview/sensitivity labels on `ctx` or `policy_context` so server-side policy can make identity-aware decisions.
|
|
1896
1933
|
- If a Foundry hosted tool executes entirely inside a remote provider runtime, this local Python SDK can protect the local request/response boundary but cannot inspect inside the remote execution environment.
|
|
1897
|
-
- Microsoft AI Foundry requires the
|
|
1934
|
+
- Microsoft AI Foundry requires the tenant runtime sidecar URL, API key, and tenant ID. Threat-contract prompt and tool analysis also require `AGENTICDOME_BEARER_TOKEN`.
|
|
1898
1935
|
|
|
1899
1936
|
Official references:
|
|
1900
1937
|
|
|
@@ -2991,7 +3028,7 @@ If you need to call AgenticDome APIs manually, use the core SDK client.
|
|
|
2991
3028
|
from agenticdome_sdk.client import AgentGuardClient
|
|
2992
3029
|
|
|
2993
3030
|
client = AgentGuardClient(
|
|
2994
|
-
api_base="https://
|
|
3031
|
+
api_base="https://demo-sidecar.agenticdome.io",
|
|
2995
3032
|
api_key="your-api-key",
|
|
2996
3033
|
tenant_id="your-tenant-id",
|
|
2997
3034
|
timeout=20,
|
|
@@ -3012,7 +3049,7 @@ client.report_incident(
|
|
|
3012
3049
|
from agenticdome_sdk.client import AgentGuardClient
|
|
3013
3050
|
|
|
3014
3051
|
client = AgentGuardClient(
|
|
3015
|
-
api_base="https://
|
|
3052
|
+
api_base="https://demo-sidecar.agenticdome.io",
|
|
3016
3053
|
api_key="your-api-key",
|
|
3017
3054
|
tenant_id="your-tenant-id",
|
|
3018
3055
|
timeout=20,
|
|
@@ -3040,7 +3077,7 @@ print(result)
|
|
|
3040
3077
|
from agenticdome_sdk.client import AgentGuardClient
|
|
3041
3078
|
|
|
3042
3079
|
client = AgentGuardClient(
|
|
3043
|
-
api_base="https://
|
|
3080
|
+
api_base="https://demo-sidecar.agenticdome.io",
|
|
3044
3081
|
api_key="your-api-key",
|
|
3045
3082
|
tenant_id="your-tenant-id",
|
|
3046
3083
|
timeout=20,
|
|
@@ -3076,7 +3113,7 @@ print(result)
|
|
|
3076
3113
|
from agenticdome_sdk.client import AgentGuardClient
|
|
3077
3114
|
|
|
3078
3115
|
client = AgentGuardClient(
|
|
3079
|
-
api_base="https://
|
|
3116
|
+
api_base="https://demo-sidecar.agenticdome.io",
|
|
3080
3117
|
api_key="your-api-key",
|
|
3081
3118
|
tenant_id="your-tenant-id",
|
|
3082
3119
|
timeout=20,
|
|
@@ -3113,7 +3150,7 @@ print(authorization)
|
|
|
3113
3150
|
from agenticdome_sdk.client import AgentGuardClient
|
|
3114
3151
|
|
|
3115
3152
|
client = AgentGuardClient(
|
|
3116
|
-
api_base="https://
|
|
3153
|
+
api_base="https://demo-sidecar.agenticdome.io",
|
|
3117
3154
|
api_key="your-api-key",
|
|
3118
3155
|
tenant_id="your-tenant-id",
|
|
3119
3156
|
timeout=20,
|
|
@@ -3144,7 +3181,7 @@ print(verification)
|
|
|
3144
3181
|
from agenticdome_sdk.client import AgentGuardClient
|
|
3145
3182
|
|
|
3146
3183
|
client = AgentGuardClient(
|
|
3147
|
-
api_base="https://
|
|
3184
|
+
api_base="https://demo-sidecar.agenticdome.io",
|
|
3148
3185
|
api_key="your-api-key",
|
|
3149
3186
|
tenant_id="your-tenant-id",
|
|
3150
3187
|
timeout=20,
|
|
@@ -3193,7 +3230,7 @@ In-memory token storage is suitable for local development and single-process wor
|
|
|
3193
3230
|
## Recommended Production Settings
|
|
3194
3231
|
|
|
3195
3232
|
```bash
|
|
3196
|
-
export AGENTICDOME_API_BASE="https://
|
|
3233
|
+
export AGENTICDOME_API_BASE="https://demo-sidecar.agenticdome.io"
|
|
3197
3234
|
export AGENTICDOME_API_KEY="your_api_key"
|
|
3198
3235
|
export AGENTICDOME_TENANT_ID="your_tenant_id"
|
|
3199
3236
|
|
|
@@ -3418,7 +3455,7 @@ For strict security-policy validation, add:
|
|
|
3418
3455
|
export AGENTICDOME_LIVE_EXPECT_STRICT=1
|
|
3419
3456
|
```
|
|
3420
3457
|
|
|
3421
|
-
The live tenant
|
|
3458
|
+
The live tenant suite performs real `guardrail_validate()` and `mesh_validate()` calls, verifies that one request can carry an originating human subject and upstream agent actor together, and queries the tenant's active threat-signature bundle through the public SDK method. With `AGENTICDOME_LIVE_EXPECT_STRICT=1`, it additionally requires sensitive output enforcement plus a signed bundle whose provenance is `agenticdome_private_collection`. Framework-specific behavior remains covered by the offline adapter test matrix above.
|
|
3422
3459
|
|
|
3423
3460
|
---
|
|
3424
3461
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
agenticdome_python_sdk-1.1.4.dist-info/licenses/LICENSE,sha256=lqAH8G9tU2WPK9fzrnM_QMd4XUrh9fsmPqKE_hniKpM,718
|
|
2
|
+
agenticdome_sdk/__init__.py,sha256=6eOHJkY_Ir51dRKTktObXS40PjUsHrWMEQ2V3N0ItN4,576
|
|
3
|
+
agenticdome_sdk/agno.py,sha256=3gbc5URNTAHyNVAaAH882CpQpMecTv0R6S0CNMDOgos,60686
|
|
4
|
+
agenticdome_sdk/aws_bedrock.py,sha256=Z1Rcbps7VgvETmq_wrUbIvg6lJxsoe7YJEPZYkBKr80,69498
|
|
5
|
+
agenticdome_sdk/client.py,sha256=rRFqW5zXVDYGqDrchy3D-HxRaDINttcgYu8VRQXnceU,48658
|
|
6
|
+
agenticdome_sdk/crewai.py,sha256=7o7yapjbGfxfHGrmKtnpERIeJlDKIRgqz2h1WpLQJkQ,52389
|
|
7
|
+
agenticdome_sdk/google_adk.py,sha256=U23uSvUxgeQRUX6fGewls0CU0GI8mru67O1mHti7RkA,57175
|
|
8
|
+
agenticdome_sdk/identity.py,sha256=mrymGgZSVsKJ9THRde54qGmMT7j_uZHmPJ-HtWk7PXE,4635
|
|
9
|
+
agenticdome_sdk/langgraph.py,sha256=9zRAjA2KeDRS28PuPiVj5XrPm2-vONfkqNvXOVoIILY,84234
|
|
10
|
+
agenticdome_sdk/llamaindex.py,sha256=uFDzeYNz4Y72W-5XdluhdHvKAc8xkPJRkPaLFvwhlSk,42777
|
|
11
|
+
agenticdome_sdk/mcp_host.py,sha256=bEGamFhnUEL-V_qP1FLTqrItpx7p9NQWlJyzUzqQcYw,59484
|
|
12
|
+
agenticdome_sdk/microsoft_agent_framework.py,sha256=uSO7cOl9rWC99KaNkLv0ciU7EWpxAxNBGmolP_CVpaA,67140
|
|
13
|
+
agenticdome_sdk/microsoft_ai_foundry.py,sha256=GkfdfW0ajSpRRoLXyo5FYAp5img0JVDUJO52wZvew1I,56803
|
|
14
|
+
agenticdome_sdk/openai_agents.py,sha256=bWoJ2hjCyXDWl5Eo4pjeRr_MOQgNOZW7QE9WRDo6oDw,57243
|
|
15
|
+
agenticdome_sdk/proof.py,sha256=ECKc14xSE0V1HHmcpZjfVz8-Q2H_fooah3BfdblFV8M,2878
|
|
16
|
+
agenticdome_sdk/pydantic.py,sha256=7R6X0JgPIMLcWO682wcpN0X8dSMVEiwvVc4ydUN111s,54882
|
|
17
|
+
agenticdome_sdk/scenarios.py,sha256=QROC_JWKwub5AdpP9pLXdJCpotEACkF-qgKAnDAo8XA,7882
|
|
18
|
+
agenticdome_python_sdk-1.1.4.dist-info/METADATA,sha256=f1Nw3Nh3QRo3WLtYR7dO1QXFBTWqR1DNWxv2zRS853E,165975
|
|
19
|
+
agenticdome_python_sdk-1.1.4.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
20
|
+
agenticdome_python_sdk-1.1.4.dist-info/top_level.txt,sha256=LZbbjXco5mqDrGwlTJpIKI5Sp6R_njzHHjExxAs9c3s,16
|
|
21
|
+
agenticdome_python_sdk-1.1.4.dist-info/RECORD,,
|
agenticdome_sdk/__init__.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
from .client import AgentGuardClient, AgentGuardError, AgentGuardHTTPError
|
|
2
|
+
from .identity import IDENTITY_CONTEXT_VERSION, canonicalize_identity_context, enrich_policy_context
|
|
3
|
+
from .proof import create_dpop_proof, generate_rsa_proof_key, jwk_thumbprint
|
|
2
4
|
|
|
3
5
|
GuardrailClient = AgentGuardClient
|
|
4
6
|
|
|
@@ -7,4 +9,10 @@ __all__ = [
|
|
|
7
9
|
"GuardrailClient",
|
|
8
10
|
"AgentGuardError",
|
|
9
11
|
"AgentGuardHTTPError",
|
|
12
|
+
"IDENTITY_CONTEXT_VERSION",
|
|
13
|
+
"canonicalize_identity_context",
|
|
14
|
+
"enrich_policy_context",
|
|
15
|
+
"create_dpop_proof",
|
|
16
|
+
"generate_rsa_proof_key",
|
|
17
|
+
"jwk_thumbprint",
|
|
10
18
|
]
|
agenticdome_sdk/client.py
CHANGED
|
@@ -6,6 +6,8 @@ import requests
|
|
|
6
6
|
from requests.adapters import HTTPAdapter
|
|
7
7
|
from urllib3.util.retry import Retry
|
|
8
8
|
|
|
9
|
+
from .identity import enrich_policy_context
|
|
10
|
+
|
|
9
11
|
|
|
10
12
|
class AgentGuardError(Exception):
|
|
11
13
|
"""Base SDK exception."""
|
|
@@ -49,12 +51,13 @@ class AgentGuardClient:
|
|
|
49
51
|
tenant_id: Optional[Union[str, int]] = None,
|
|
50
52
|
bearer_token: Optional[str] = None,
|
|
51
53
|
timeout: int = 20,
|
|
52
|
-
user_agent: str = "agenticdome-python-sdk/
|
|
54
|
+
user_agent: str = "agenticdome-python-sdk/1.1.3",
|
|
53
55
|
max_retries: int = 3,
|
|
54
56
|
connect_timeout: Optional[float] = None,
|
|
55
57
|
pool_connections: int = 20,
|
|
56
58
|
pool_maxsize: int = 100,
|
|
57
59
|
pool_block: bool = False,
|
|
60
|
+
service_token: Optional[str] = None,
|
|
58
61
|
):
|
|
59
62
|
self.api_base = self._require_nonempty("api_base", api_base).rstrip("/")
|
|
60
63
|
self.api_key = self._require_nonempty(
|
|
@@ -69,6 +72,11 @@ class AgentGuardClient:
|
|
|
69
72
|
bearer_token
|
|
70
73
|
or os.getenv("AGENTICDOME_BEARER_TOKEN")
|
|
71
74
|
)
|
|
75
|
+
self.service_token = (
|
|
76
|
+
service_token
|
|
77
|
+
or os.getenv("AGENTICDOME_SERVICE_TOKEN")
|
|
78
|
+
or os.getenv("SERVICE_SECRET")
|
|
79
|
+
)
|
|
72
80
|
self.timeout = timeout
|
|
73
81
|
self.connect_timeout = self._positive_float(
|
|
74
82
|
"connect_timeout",
|
|
@@ -194,7 +202,11 @@ class AgentGuardClient:
|
|
|
194
202
|
for key, value in top_level_values.items():
|
|
195
203
|
if value is not None:
|
|
196
204
|
pc[key] = value
|
|
197
|
-
return
|
|
205
|
+
return enrich_policy_context(
|
|
206
|
+
pc,
|
|
207
|
+
platform=pc.get("platform"),
|
|
208
|
+
target_agent_id=pc.get("target_agent_id") or pc.get("agent_id"),
|
|
209
|
+
)
|
|
198
210
|
|
|
199
211
|
def _validate_guardrail_args(
|
|
200
212
|
self,
|
|
@@ -226,9 +238,6 @@ class AgentGuardClient:
|
|
|
226
238
|
|
|
227
239
|
normalized_direction = self._normalize_direction(direction)
|
|
228
240
|
|
|
229
|
-
if source_agent_id and user_id:
|
|
230
|
-
raise ValueError("Provide either 'source_agent_id' or 'user_id', not both")
|
|
231
|
-
|
|
232
241
|
if tool_name and tool_args is None:
|
|
233
242
|
raise ValueError("'tool_args' is required when 'tool_name' is provided")
|
|
234
243
|
if tool_args is not None and not tool_name:
|
|
@@ -302,6 +311,24 @@ class AgentGuardClient:
|
|
|
302
311
|
except Exception as exc:
|
|
303
312
|
raise AgentGuardError(f"Failed to decode JSON response from {url}: {exc}") from exc
|
|
304
313
|
|
|
314
|
+
def _protected_request(
|
|
315
|
+
self,
|
|
316
|
+
method: str,
|
|
317
|
+
path: str,
|
|
318
|
+
*,
|
|
319
|
+
json_body: Optional[Dict[str, Any]] = None,
|
|
320
|
+
tenant_id: Optional[Union[str, int]] = None,
|
|
321
|
+
) -> Dict[str, Any]:
|
|
322
|
+
headers = {"X-Service-Token": self.service_token} if self.service_token else None
|
|
323
|
+
return self._request(
|
|
324
|
+
method,
|
|
325
|
+
path,
|
|
326
|
+
json_body=json_body,
|
|
327
|
+
tenant_id=tenant_id,
|
|
328
|
+
use_bearer=bool(not self.service_token and self.bearer_token),
|
|
329
|
+
extra_headers=headers,
|
|
330
|
+
)
|
|
331
|
+
|
|
305
332
|
# ------------------------------------------------------------------
|
|
306
333
|
# SaaS Scan Endpoints
|
|
307
334
|
# ------------------------------------------------------------------
|
|
@@ -478,6 +505,7 @@ class AgentGuardClient:
|
|
|
478
505
|
|
|
479
506
|
merged_policy_context = self._merge_policy_context(
|
|
480
507
|
policy_context,
|
|
508
|
+
agent_id=agent_id,
|
|
481
509
|
platform=platform,
|
|
482
510
|
source_platform=source_platform,
|
|
483
511
|
tool_platform=tool_platform,
|
|
@@ -602,6 +630,7 @@ class AgentGuardClient:
|
|
|
602
630
|
|
|
603
631
|
merged_policy_context = self._merge_policy_context(
|
|
604
632
|
policy_context,
|
|
633
|
+
agent_id=agent_id,
|
|
605
634
|
platform=effective_platform,
|
|
606
635
|
source_platform=source_platform,
|
|
607
636
|
source_agent_id=source_agent_id,
|
|
@@ -651,7 +680,33 @@ class AgentGuardClient:
|
|
|
651
680
|
is_agent: bool = True,
|
|
652
681
|
) -> Dict[str, Any]:
|
|
653
682
|
path = f"/trust/score/{agent_id}?is_agent={'true' if is_agent else 'false'}"
|
|
654
|
-
return self.
|
|
683
|
+
return self._protected_request("GET", path, tenant_id=tenant_id)
|
|
684
|
+
|
|
685
|
+
def get_behavioral_attestation(
|
|
686
|
+
self,
|
|
687
|
+
agent_id: str,
|
|
688
|
+
tenant_id: Optional[Union[str, int]] = None,
|
|
689
|
+
) -> Dict[str, Any]:
|
|
690
|
+
self._require_nonempty("agent_id", agent_id)
|
|
691
|
+
return self._protected_request("GET", f"/trust/behavior/{agent_id}", tenant_id=tenant_id)
|
|
692
|
+
|
|
693
|
+
def get_behavioral_summary(
|
|
694
|
+
self,
|
|
695
|
+
tenant_id: Optional[Union[str, int]] = None,
|
|
696
|
+
limit: int = 300,
|
|
697
|
+
) -> Dict[str, Any]:
|
|
698
|
+
bounded_limit = max(1, min(int(limit), 1000))
|
|
699
|
+
return self._protected_request(
|
|
700
|
+
"GET",
|
|
701
|
+
f"/trust/behavior-summary?limit={bounded_limit}",
|
|
702
|
+
tenant_id=tenant_id,
|
|
703
|
+
)
|
|
704
|
+
|
|
705
|
+
def get_threat_signature_status(
|
|
706
|
+
self,
|
|
707
|
+
tenant_id: Optional[Union[str, int]] = None,
|
|
708
|
+
) -> Dict[str, Any]:
|
|
709
|
+
return self._protected_request("GET", "/security/threat-signatures/status", tenant_id=tenant_id)
|
|
655
710
|
|
|
656
711
|
def report_incident(
|
|
657
712
|
self,
|
|
@@ -672,7 +727,7 @@ class AgentGuardClient:
|
|
|
672
727
|
"is_agent": is_agent,
|
|
673
728
|
"platform": platform or "unknown",
|
|
674
729
|
}
|
|
675
|
-
return self.
|
|
730
|
+
return self._protected_request("POST", "/trust/report", json_body=payload, tenant_id=tenant_id)
|
|
676
731
|
|
|
677
732
|
def reset_trust_score(
|
|
678
733
|
self,
|
|
@@ -682,7 +737,7 @@ class AgentGuardClient:
|
|
|
682
737
|
is_agent: bool = True,
|
|
683
738
|
service_token: Optional[str] = None,
|
|
684
739
|
) -> Dict[str, Any]:
|
|
685
|
-
token = service_token or admin_secret or
|
|
740
|
+
token = service_token or admin_secret or self.service_token
|
|
686
741
|
if not token:
|
|
687
742
|
raise ValueError("reset_trust_score requires service_token or AGENTICDOME_SERVICE_TOKEN")
|
|
688
743
|
path = f"/trust/reset/{agent_id}?is_agent={'true' if is_agent else 'false'}"
|
|
@@ -742,6 +797,16 @@ class AgentGuardClient:
|
|
|
742
797
|
block_on_sensitive_output: Optional[bool] = None,
|
|
743
798
|
trusted_destination_domains: Optional[List[str]] = None,
|
|
744
799
|
allowed_destination_domains: Optional[List[str]] = None,
|
|
800
|
+
user_id: Optional[str] = None,
|
|
801
|
+
actor_chain: Optional[List[Dict[str, Any]]] = None,
|
|
802
|
+
scopes: Optional[List[str]] = None,
|
|
803
|
+
permissions: Optional[List[str]] = None,
|
|
804
|
+
parent_jti: Optional[str] = None,
|
|
805
|
+
root_jti: Optional[str] = None,
|
|
806
|
+
policy_id: Optional[str] = None,
|
|
807
|
+
policy_version: Optional[str] = None,
|
|
808
|
+
policy_hash: Optional[str] = None,
|
|
809
|
+
proof_thumbprint: Optional[str] = None,
|
|
745
810
|
tenant_id: Optional[Union[str, int]] = None,
|
|
746
811
|
request_id: Union[str, int] = "1",
|
|
747
812
|
) -> Dict[str, Any]:
|
|
@@ -779,6 +844,7 @@ class AgentGuardClient:
|
|
|
779
844
|
|
|
780
845
|
merged_policy_context = self._merge_policy_context(
|
|
781
846
|
policy_context,
|
|
847
|
+
agent_id=agent_id,
|
|
782
848
|
platform=platform,
|
|
783
849
|
source_platform=source_platform,
|
|
784
850
|
tool_platform=tool_platform,
|
|
@@ -798,6 +864,16 @@ class AgentGuardClient:
|
|
|
798
864
|
block_on_sensitive_output=block_on_sensitive_output,
|
|
799
865
|
trusted_destination_domains=trusted_destination_domains,
|
|
800
866
|
allowed_destination_domains=allowed_destination_domains,
|
|
867
|
+
user_id=user_id,
|
|
868
|
+
actor_chain=actor_chain,
|
|
869
|
+
scopes=scopes,
|
|
870
|
+
permissions=permissions,
|
|
871
|
+
parent_jti=parent_jti,
|
|
872
|
+
root_jti=root_jti,
|
|
873
|
+
policy_id=policy_id,
|
|
874
|
+
policy_version=policy_version,
|
|
875
|
+
policy_hash=policy_hash,
|
|
876
|
+
proof_thumbprint=proof_thumbprint,
|
|
801
877
|
)
|
|
802
878
|
|
|
803
879
|
arguments = self._drop_none(
|
|
@@ -826,6 +902,16 @@ class AgentGuardClient:
|
|
|
826
902
|
"block_on_sensitive_output": block_on_sensitive_output,
|
|
827
903
|
"trusted_destination_domains": trusted_destination_domains,
|
|
828
904
|
"allowed_destination_domains": allowed_destination_domains,
|
|
905
|
+
"user_id": user_id,
|
|
906
|
+
"actor_chain": actor_chain,
|
|
907
|
+
"scopes": scopes,
|
|
908
|
+
"permissions": permissions,
|
|
909
|
+
"parent_jti": parent_jti,
|
|
910
|
+
"root_jti": root_jti,
|
|
911
|
+
"policy_id": policy_id,
|
|
912
|
+
"policy_version": policy_version,
|
|
913
|
+
"policy_hash": policy_hash,
|
|
914
|
+
"proof_thumbprint": proof_thumbprint,
|
|
829
915
|
}
|
|
830
916
|
)
|
|
831
917
|
|
|
@@ -854,7 +940,12 @@ class AgentGuardClient:
|
|
|
854
940
|
agent_id: Optional[str] = None,
|
|
855
941
|
source_agent_id: Optional[str] = None,
|
|
856
942
|
platform: Optional[str] = None,
|
|
943
|
+
user_id: Optional[str] = None,
|
|
944
|
+
session_id: Optional[str] = None,
|
|
945
|
+
proof_thumbprint: Optional[str] = None,
|
|
946
|
+
proof_token: Optional[str] = None,
|
|
857
947
|
require_allowed: bool = True,
|
|
948
|
+
consume: bool = True,
|
|
858
949
|
tenant_id: Optional[Union[str, int]] = None,
|
|
859
950
|
) -> Dict[str, Any]:
|
|
860
951
|
"""
|
|
@@ -881,7 +972,12 @@ class AgentGuardClient:
|
|
|
881
972
|
"agent_id": agent_id,
|
|
882
973
|
"source_agent_id": source_agent_id,
|
|
883
974
|
"platform": platform,
|
|
975
|
+
"user_id": user_id,
|
|
976
|
+
"session_id": session_id,
|
|
977
|
+
"proof_thumbprint": proof_thumbprint,
|
|
978
|
+
"proof_token": proof_token,
|
|
884
979
|
"require_allowed": require_allowed,
|
|
980
|
+
"consume": consume,
|
|
885
981
|
}
|
|
886
982
|
)
|
|
887
983
|
|
|
@@ -896,7 +992,12 @@ class AgentGuardClient:
|
|
|
896
992
|
agent_id: Optional[str] = None,
|
|
897
993
|
source_agent_id: Optional[str] = None,
|
|
898
994
|
platform: Optional[str] = None,
|
|
995
|
+
user_id: Optional[str] = None,
|
|
996
|
+
session_id: Optional[str] = None,
|
|
997
|
+
proof_thumbprint: Optional[str] = None,
|
|
998
|
+
proof_token: Optional[str] = None,
|
|
899
999
|
require_allowed: bool = True,
|
|
1000
|
+
consume: bool = True,
|
|
900
1001
|
tenant_id: Optional[Union[str, int]] = None,
|
|
901
1002
|
request_id: Union[str, int] = "1",
|
|
902
1003
|
) -> Dict[str, Any]:
|
|
@@ -924,7 +1025,12 @@ class AgentGuardClient:
|
|
|
924
1025
|
"agent_id": agent_id,
|
|
925
1026
|
"source_agent_id": source_agent_id,
|
|
926
1027
|
"platform": platform,
|
|
1028
|
+
"user_id": user_id,
|
|
1029
|
+
"session_id": session_id,
|
|
1030
|
+
"proof_thumbprint": proof_thumbprint,
|
|
1031
|
+
"proof_token": proof_token,
|
|
927
1032
|
"require_allowed": require_allowed,
|
|
1033
|
+
"consume": consume,
|
|
928
1034
|
}
|
|
929
1035
|
)
|
|
930
1036
|
|
|
@@ -935,6 +1041,44 @@ class AgentGuardClient:
|
|
|
935
1041
|
tenant_id=tenant_id,
|
|
936
1042
|
)
|
|
937
1043
|
|
|
1044
|
+
def get_decision_token_status(
|
|
1045
|
+
self,
|
|
1046
|
+
jti: str,
|
|
1047
|
+
*,
|
|
1048
|
+
tenant_id: Optional[Union[str, int]] = None,
|
|
1049
|
+
) -> Dict[str, Any]:
|
|
1050
|
+
self._require_nonempty("jti", jti)
|
|
1051
|
+
return self._request(
|
|
1052
|
+
"GET",
|
|
1053
|
+
f"/a2a/decision/status/{jti}",
|
|
1054
|
+
tenant_id=tenant_id,
|
|
1055
|
+
)
|
|
1056
|
+
|
|
1057
|
+
def revoke_decision_token(
|
|
1058
|
+
self,
|
|
1059
|
+
*,
|
|
1060
|
+
jti: Optional[str] = None,
|
|
1061
|
+
root_jti: Optional[str] = None,
|
|
1062
|
+
agent_id: Optional[str] = None,
|
|
1063
|
+
user_id: Optional[str] = None,
|
|
1064
|
+
reason: str = "revoked by tenant administrator",
|
|
1065
|
+
tenant_id: Optional[Union[str, int]] = None,
|
|
1066
|
+
) -> Dict[str, Any]:
|
|
1067
|
+
if not any(self._normalize_optional_string(value) for value in (jti, root_jti, agent_id, user_id)):
|
|
1068
|
+
raise ValueError("revoke_decision_token requires jti, root_jti, agent_id, or user_id")
|
|
1069
|
+
return self._request(
|
|
1070
|
+
"POST",
|
|
1071
|
+
"/a2a/decision/revoke",
|
|
1072
|
+
json_body=self._drop_none({
|
|
1073
|
+
"jti": jti,
|
|
1074
|
+
"root_jti": root_jti,
|
|
1075
|
+
"agent_id": agent_id,
|
|
1076
|
+
"user_id": user_id,
|
|
1077
|
+
"reason": reason,
|
|
1078
|
+
}),
|
|
1079
|
+
tenant_id=tenant_id,
|
|
1080
|
+
)
|
|
1081
|
+
|
|
938
1082
|
# ------------------------------------------------------------------
|
|
939
1083
|
# MCP JSON-RPC
|
|
940
1084
|
# ------------------------------------------------------------------
|
|
@@ -1136,7 +1280,7 @@ class AgentGuardClient:
|
|
|
1136
1280
|
"attack_profiles": attack_profiles or ["prompt_injection", "pii_leak"],
|
|
1137
1281
|
"context": context,
|
|
1138
1282
|
}
|
|
1139
|
-
return self.
|
|
1283
|
+
return self._protected_request("POST", "/security/", json_body=payload, tenant_id=tenant_id)
|
|
1140
1284
|
|
|
1141
1285
|
# ------------------------------------------------------------------
|
|
1142
1286
|
# Convenience scenario builders
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
import json
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
IDENTITY_CONTEXT_VERSION = "agenticdome.identity.v1"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _text(value: Any) -> str:
|
|
12
|
+
return str(value or "").strip()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _list(value: Any) -> list[str]:
|
|
16
|
+
if value is None:
|
|
17
|
+
return []
|
|
18
|
+
if isinstance(value, str):
|
|
19
|
+
value = value.replace(",", " ").split()
|
|
20
|
+
if not isinstance(value, (list, tuple, set)):
|
|
21
|
+
value = [value]
|
|
22
|
+
return sorted({_text(item) for item in value if _text(item)})
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _hash(value: Any) -> str:
|
|
26
|
+
raw = json.dumps(value, sort_keys=True, separators=(",", ":"), default=str).encode("utf-8")
|
|
27
|
+
return "sha256:" + hashlib.sha256(raw).hexdigest()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def canonicalize_identity_context(
|
|
31
|
+
policy_context: dict[str, Any] | None,
|
|
32
|
+
*,
|
|
33
|
+
platform: str | None = None,
|
|
34
|
+
target_agent_id: str | None = None,
|
|
35
|
+
) -> dict[str, Any]:
|
|
36
|
+
context = dict(policy_context or {})
|
|
37
|
+
existing = context.get("agenticdome_identity")
|
|
38
|
+
if isinstance(existing, dict) and existing.get("version") == IDENTITY_CONTEXT_VERSION:
|
|
39
|
+
return existing
|
|
40
|
+
|
|
41
|
+
claims = context.get("verified_identity_claims")
|
|
42
|
+
claims = dict(claims) if isinstance(claims, dict) else {}
|
|
43
|
+
asserted_subject = _text(claims.get("oid") or claims.get("sub") or claims.get("user_id"))
|
|
44
|
+
runtime_subject = _text(context.get("user_id") or context.get("principal_id") or context.get("caller_id"))
|
|
45
|
+
subject_id = runtime_subject or asserted_subject
|
|
46
|
+
|
|
47
|
+
subject = None
|
|
48
|
+
if subject_id:
|
|
49
|
+
subject = {
|
|
50
|
+
"id": subject_id,
|
|
51
|
+
"type": "human" if runtime_subject or claims.get("oid") else "principal",
|
|
52
|
+
"tenant_id": _text(claims.get("tid") or context.get("entra_tenant_id") or context.get("tenant_id")) or None,
|
|
53
|
+
"issuer": _text(claims.get("iss") or context.get("issuer")) or None,
|
|
54
|
+
"provenance": "runtime_context" if runtime_subject else "client_claim_assertion",
|
|
55
|
+
"verified": False,
|
|
56
|
+
"attributes": {
|
|
57
|
+
"asserted_roles": _list(claims.get("roles") or context.get("roles")),
|
|
58
|
+
"asserted_scopes": _list(claims.get("scp") or context.get("scp")),
|
|
59
|
+
},
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
raw_chain = context.get("actor_chain") or context.get("delegation_chain") or []
|
|
63
|
+
if not isinstance(raw_chain, list):
|
|
64
|
+
raw_chain = [raw_chain]
|
|
65
|
+
actors: list[dict[str, Any]] = []
|
|
66
|
+
for item in raw_chain:
|
|
67
|
+
if len(actors) >= 32:
|
|
68
|
+
break
|
|
69
|
+
if isinstance(item, dict):
|
|
70
|
+
actor_id = _text(item.get("id") or item.get("sub") or item.get("agent_id"))
|
|
71
|
+
framework = _text(item.get("framework") or item.get("platform"))
|
|
72
|
+
verified = False
|
|
73
|
+
provenance = "client_runtime_assertion"
|
|
74
|
+
else:
|
|
75
|
+
actor_id = _text(item)
|
|
76
|
+
framework = ""
|
|
77
|
+
verified = False
|
|
78
|
+
provenance = "runtime_context"
|
|
79
|
+
if actor_id and len(actor_id) <= 512 and not any(actor["id"] == actor_id for actor in actors):
|
|
80
|
+
actors.append({
|
|
81
|
+
"id": actor_id,
|
|
82
|
+
"type": "agent",
|
|
83
|
+
"framework": framework or None,
|
|
84
|
+
"verified": verified,
|
|
85
|
+
"provenance": provenance,
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
for actor_id, framework in (
|
|
89
|
+
(context.get("source_agent_id"), context.get("source_platform") or platform),
|
|
90
|
+
(target_agent_id or context.get("target_agent_id") or context.get("agent_id"), context.get("platform") or platform),
|
|
91
|
+
):
|
|
92
|
+
if len(actors) >= 32:
|
|
93
|
+
break
|
|
94
|
+
value = _text(actor_id)
|
|
95
|
+
if value and not any(actor["id"] == value for actor in actors):
|
|
96
|
+
actors.append({
|
|
97
|
+
"id": value,
|
|
98
|
+
"type": "agent",
|
|
99
|
+
"framework": _text(framework) or None,
|
|
100
|
+
"verified": False,
|
|
101
|
+
"provenance": "request_binding",
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
"version": IDENTITY_CONTEXT_VERSION,
|
|
106
|
+
"framework": _text(platform or context.get("platform")) or "unknown",
|
|
107
|
+
"subject": subject,
|
|
108
|
+
"actors": actors,
|
|
109
|
+
"provenance": {
|
|
110
|
+
"client_claims_asserted": bool(claims),
|
|
111
|
+
"verified_claims_present": False,
|
|
112
|
+
"native_context_hash": _hash(context),
|
|
113
|
+
},
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def enrich_policy_context(
|
|
118
|
+
policy_context: dict[str, Any] | None,
|
|
119
|
+
*,
|
|
120
|
+
platform: str | None = None,
|
|
121
|
+
target_agent_id: str | None = None,
|
|
122
|
+
) -> dict[str, Any]:
|
|
123
|
+
context = dict(policy_context or {})
|
|
124
|
+
context["agenticdome_identity"] = canonicalize_identity_context(
|
|
125
|
+
context,
|
|
126
|
+
platform=platform,
|
|
127
|
+
target_agent_id=target_agent_id,
|
|
128
|
+
)
|
|
129
|
+
return context
|
agenticdome_sdk/langgraph.py
CHANGED
|
@@ -1111,6 +1111,20 @@ class AgenticDomeLangGraphFirewall:
|
|
|
1111
1111
|
ns = _state_ns(state)
|
|
1112
1112
|
if isinstance(ns.get("policy_context"), dict):
|
|
1113
1113
|
ctx.update(cast(Dict[str, Any], ns["policy_context"]))
|
|
1114
|
+
lineage = ns.get("lineage_context")
|
|
1115
|
+
if isinstance(lineage, dict):
|
|
1116
|
+
for key in (
|
|
1117
|
+
"user_id",
|
|
1118
|
+
"actor_chain",
|
|
1119
|
+
"root_jti",
|
|
1120
|
+
"parent_jti",
|
|
1121
|
+
"scopes",
|
|
1122
|
+
"policy_id",
|
|
1123
|
+
"policy_version",
|
|
1124
|
+
"policy_hash",
|
|
1125
|
+
):
|
|
1126
|
+
if lineage.get(key) is not None and key not in ctx:
|
|
1127
|
+
ctx[key] = lineage[key]
|
|
1114
1128
|
|
|
1115
1129
|
ctx.setdefault("source_agent_id", agent_id)
|
|
1116
1130
|
ctx.setdefault("request_purpose", default_request_purpose)
|
|
@@ -1136,6 +1150,23 @@ class AgenticDomeLangGraphFirewall:
|
|
|
1136
1150
|
|
|
1137
1151
|
return ctx
|
|
1138
1152
|
|
|
1153
|
+
def _capture_verified_lineage(self, state: AgentState, verification: Dict[str, Any]) -> None:
|
|
1154
|
+
claims = verification.get("claims") if isinstance(verification.get("claims"), dict) else {}
|
|
1155
|
+
if not claims:
|
|
1156
|
+
return
|
|
1157
|
+
subject = claims.get("subject") if isinstance(claims.get("subject"), dict) else {}
|
|
1158
|
+
policy = claims.get("policy") if isinstance(claims.get("policy"), dict) else {}
|
|
1159
|
+
_state_ns(state)["lineage_context"] = {
|
|
1160
|
+
"user_id": claims.get("user_id") or subject.get("id"),
|
|
1161
|
+
"actor_chain": claims.get("actor_chain") or [],
|
|
1162
|
+
"root_jti": claims.get("root_jti") or claims.get("jti"),
|
|
1163
|
+
"parent_jti": claims.get("jti"),
|
|
1164
|
+
"scopes": claims.get("scopes") or [],
|
|
1165
|
+
"policy_id": policy.get("id"),
|
|
1166
|
+
"policy_version": policy.get("version"),
|
|
1167
|
+
"policy_hash": policy.get("hash"),
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1139
1170
|
def _extract_explicit_handoff(self, state: AgentState) -> Optional[Dict[str, Any]]:
|
|
1140
1171
|
ns = _state_ns(state)
|
|
1141
1172
|
raw = ns.get("handoff") or cast(Dict[str, Any], state).get("handoff")
|
|
@@ -1261,6 +1292,7 @@ class AgenticDomeLangGraphFirewall:
|
|
|
1261
1292
|
if not valid:
|
|
1262
1293
|
raise AgenticDomeDenied(f"AgenticDome blocked delegated execution: {_reason(verification)}")
|
|
1263
1294
|
|
|
1295
|
+
self._capture_verified_lineage(state, verification)
|
|
1264
1296
|
self._clear_delegation_state(state)
|
|
1265
1297
|
return
|
|
1266
1298
|
|
|
@@ -1287,6 +1319,7 @@ class AgenticDomeLangGraphFirewall:
|
|
|
1287
1319
|
)
|
|
1288
1320
|
if not valid:
|
|
1289
1321
|
raise AgenticDomeDenied(f"AgenticDome blocked delegated execution: {_reason(verification)}")
|
|
1322
|
+
self._capture_verified_lineage(state, verification)
|
|
1290
1323
|
return
|
|
1291
1324
|
|
|
1292
1325
|
pending = self.token_store.consume(
|
|
@@ -1312,6 +1345,7 @@ class AgenticDomeLangGraphFirewall:
|
|
|
1312
1345
|
)
|
|
1313
1346
|
if not valid:
|
|
1314
1347
|
raise AgenticDomeDenied(f"AgenticDome blocked delegated execution: {_reason(verification)}")
|
|
1348
|
+
self._capture_verified_lineage(state, verification)
|
|
1315
1349
|
self._audit("delegated_execution_allowed", agent_id=agent_id, source_agent_id=pending.source_agent_id, tool_name=tool_name)
|
|
1316
1350
|
return
|
|
1317
1351
|
|
|
@@ -562,6 +562,7 @@ class AgenticDomeMicrosoftAIFoundryFirewall:
|
|
|
562
562
|
for key in (
|
|
563
563
|
"tenant_id", "entra_tenant_id", "oid", "object_id", "appid", "app_id", "client_id",
|
|
564
564
|
"upn", "username", "email", "roles", "scp", "azp", "purview_label",
|
|
565
|
+
"user_id", "principal_id", "caller_id",
|
|
565
566
|
"sensitivity_label", "data_classification", "foundry_project_id", "foundry_agent_id",
|
|
566
567
|
):
|
|
567
568
|
value = self._ctx_attr(ctx, key, default=None)
|
agenticdome_sdk/proof.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import base64
|
|
4
|
+
import hashlib
|
|
5
|
+
import json
|
|
6
|
+
import time
|
|
7
|
+
import uuid
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _crypto():
|
|
12
|
+
try:
|
|
13
|
+
from cryptography.hazmat.primitives import hashes, serialization
|
|
14
|
+
from cryptography.hazmat.primitives.asymmetric import padding, rsa
|
|
15
|
+
except ImportError as exc:
|
|
16
|
+
raise RuntimeError(
|
|
17
|
+
"Proof-of-possession helpers require: pip install 'agenticdome-python-sdk[pop]'"
|
|
18
|
+
) from exc
|
|
19
|
+
return hashes, serialization, padding, rsa
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _b64u(data: bytes) -> str:
|
|
23
|
+
return base64.urlsafe_b64encode(data).decode("ascii").rstrip("=")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _public_jwk(private_key) -> dict[str, str]:
|
|
27
|
+
numbers = private_key.public_key().public_numbers()
|
|
28
|
+
return {
|
|
29
|
+
"kty": "RSA",
|
|
30
|
+
"n": _b64u(numbers.n.to_bytes((numbers.n.bit_length() + 7) // 8, "big")),
|
|
31
|
+
"e": _b64u(numbers.e.to_bytes((numbers.e.bit_length() + 7) // 8, "big")),
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def jwk_thumbprint(jwk: dict[str, Any]) -> str:
|
|
36
|
+
canonical = json.dumps(
|
|
37
|
+
{key: jwk[key] for key in ("e", "kty", "n")},
|
|
38
|
+
sort_keys=True,
|
|
39
|
+
separators=(",", ":"),
|
|
40
|
+
).encode("utf-8")
|
|
41
|
+
return _b64u(hashlib.sha256(canonical).digest())
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def generate_rsa_proof_key(*, key_size: int = 2048) -> dict[str, Any]:
|
|
45
|
+
_, serialization, _, rsa = _crypto()
|
|
46
|
+
private_key = rsa.generate_private_key(public_exponent=65537, key_size=max(2048, key_size))
|
|
47
|
+
private_pem = private_key.private_bytes(
|
|
48
|
+
encoding=serialization.Encoding.PEM,
|
|
49
|
+
format=serialization.PrivateFormat.PKCS8,
|
|
50
|
+
encryption_algorithm=serialization.NoEncryption(),
|
|
51
|
+
).decode("ascii")
|
|
52
|
+
jwk = _public_jwk(private_key)
|
|
53
|
+
return {"private_key_pem": private_pem, "public_jwk": jwk, "thumbprint": jwk_thumbprint(jwk)}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def create_dpop_proof(
|
|
57
|
+
private_key_pem: str,
|
|
58
|
+
*,
|
|
59
|
+
access_token: str,
|
|
60
|
+
method: str,
|
|
61
|
+
uri: str,
|
|
62
|
+
proof_jti: str | None = None,
|
|
63
|
+
issued_at: int | None = None,
|
|
64
|
+
) -> str:
|
|
65
|
+
hashes, serialization, padding, _ = _crypto()
|
|
66
|
+
private_key = serialization.load_pem_private_key(private_key_pem.encode("ascii"), password=None)
|
|
67
|
+
jwk = _public_jwk(private_key)
|
|
68
|
+
header = {"typ": "dpop+jwt", "alg": "RS256", "jwk": jwk}
|
|
69
|
+
payload = {
|
|
70
|
+
"jti": proof_jti or uuid.uuid4().hex,
|
|
71
|
+
"iat": int(issued_at or time.time()),
|
|
72
|
+
"htm": str(method).upper(),
|
|
73
|
+
"htu": str(uri),
|
|
74
|
+
"ath": _b64u(hashlib.sha256(access_token.encode("utf-8")).digest()),
|
|
75
|
+
}
|
|
76
|
+
encoded_header = _b64u(json.dumps(header, sort_keys=True, separators=(",", ":")).encode("utf-8"))
|
|
77
|
+
encoded_payload = _b64u(json.dumps(payload, sort_keys=True, separators=(",", ":")).encode("utf-8"))
|
|
78
|
+
signing_input = f"{encoded_header}.{encoded_payload}".encode("ascii")
|
|
79
|
+
signature = private_key.sign(signing_input, padding.PKCS1v15(), hashes.SHA256())
|
|
80
|
+
return f"{encoded_header}.{encoded_payload}.{_b64u(signature)}"
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
agenticdome_python_sdk-1.1.2.dist-info/licenses/LICENSE,sha256=lqAH8G9tU2WPK9fzrnM_QMd4XUrh9fsmPqKE_hniKpM,718
|
|
2
|
-
agenticdome_sdk/__init__.py,sha256=87__SX3oTttDLur7z8BhzAe6QMOSK1GXjoaTZRVTbc0,223
|
|
3
|
-
agenticdome_sdk/agno.py,sha256=3gbc5URNTAHyNVAaAH882CpQpMecTv0R6S0CNMDOgos,60686
|
|
4
|
-
agenticdome_sdk/aws_bedrock.py,sha256=Z1Rcbps7VgvETmq_wrUbIvg6lJxsoe7YJEPZYkBKr80,69498
|
|
5
|
-
agenticdome_sdk/client.py,sha256=9OJqaE5OMr7_mcqFI5b_QodQU-ZP9LxgRRoUU38rYW0,43513
|
|
6
|
-
agenticdome_sdk/crewai.py,sha256=7o7yapjbGfxfHGrmKtnpERIeJlDKIRgqz2h1WpLQJkQ,52389
|
|
7
|
-
agenticdome_sdk/google_adk.py,sha256=U23uSvUxgeQRUX6fGewls0CU0GI8mru67O1mHti7RkA,57175
|
|
8
|
-
agenticdome_sdk/langgraph.py,sha256=Eyaq-zcScLVlvT4VBHPN1H_K1An45LI7lKi0YgsXCOs,82660
|
|
9
|
-
agenticdome_sdk/llamaindex.py,sha256=uFDzeYNz4Y72W-5XdluhdHvKAc8xkPJRkPaLFvwhlSk,42777
|
|
10
|
-
agenticdome_sdk/mcp_host.py,sha256=bEGamFhnUEL-V_qP1FLTqrItpx7p9NQWlJyzUzqQcYw,59484
|
|
11
|
-
agenticdome_sdk/microsoft_agent_framework.py,sha256=W0zP49u_jucyMcSsuCM9bfdOnuRclKeu18nakaCfwq0,67064
|
|
12
|
-
agenticdome_sdk/microsoft_ai_foundry.py,sha256=aIofnEUKU30P-4vKkWx1YdZZVHQIZECjEmoMLzvrp4g,56751
|
|
13
|
-
agenticdome_sdk/openai_agents.py,sha256=bWoJ2hjCyXDWl5Eo4pjeRr_MOQgNOZW7QE9WRDo6oDw,57243
|
|
14
|
-
agenticdome_sdk/pydantic.py,sha256=7R6X0JgPIMLcWO682wcpN0X8dSMVEiwvVc4ydUN111s,54882
|
|
15
|
-
agenticdome_sdk/scenarios.py,sha256=QROC_JWKwub5AdpP9pLXdJCpotEACkF-qgKAnDAo8XA,7882
|
|
16
|
-
agenticdome_python_sdk-1.1.2.dist-info/METADATA,sha256=GHTOzz2LHgIz8fSzDkj1tICoBiD5ZO7p4wOoFUWnCuo,163986
|
|
17
|
-
agenticdome_python_sdk-1.1.2.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
18
|
-
agenticdome_python_sdk-1.1.2.dist-info/top_level.txt,sha256=LZbbjXco5mqDrGwlTJpIKI5Sp6R_njzHHjExxAs9c3s,16
|
|
19
|
-
agenticdome_python_sdk-1.1.2.dist-info/RECORD,,
|
{agenticdome_python_sdk-1.1.2.dist-info → agenticdome_python_sdk-1.1.4.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{agenticdome_python_sdk-1.1.2.dist-info → agenticdome_python_sdk-1.1.4.dist-info}/top_level.txt
RENAMED
|
File without changes
|