truceptor 0.3.2__tar.gz
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.
- truceptor-0.3.2/LICENSE +21 -0
- truceptor-0.3.2/MANIFEST.in +1 -0
- truceptor-0.3.2/PKG-INFO +401 -0
- truceptor-0.3.2/README.md +375 -0
- truceptor-0.3.2/acp/__init__.py +16 -0
- truceptor-0.3.2/acp/bundle/dashboard/app.js +1564 -0
- truceptor-0.3.2/acp/bundle/dashboard/index.html +123 -0
- truceptor-0.3.2/acp/bundle/dashboard/styles.css +1114 -0
- truceptor-0.3.2/acp/bundle/docker-compose.yml +82 -0
- truceptor-0.3.2/acp/bundle/interceptor/Dockerfile +16 -0
- truceptor-0.3.2/acp/bundle/interceptor/README.md +105 -0
- truceptor-0.3.2/acp/bundle/interceptor/api/openapi.yaml +220 -0
- truceptor-0.3.2/acp/bundle/interceptor/cmd/server/main.go +41 -0
- truceptor-0.3.2/acp/bundle/interceptor/go.mod +47 -0
- truceptor-0.3.2/acp/bundle/interceptor/go.sum +111 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/approval/errors.go +10 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/approval/repository.go +12 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/approval/store.go +221 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/approval/store_test.go +47 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/approval/sync.go +48 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/approval/sync_test.go +53 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/audit/events.go +6 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/audit/logger.go +53 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/audit/store.go +116 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/audit/store_iface.go +9 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/auth/context.go +41 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/auth/load.go +42 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/auth/principal.go +9 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/auth/validator.go +168 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/auth/validator_test.go +61 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/config/config.go +24 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/config/env.go +83 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/gateway/bootstrap.go +51 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/gateway/router.go +36 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/gateway/routes.go +42 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/gateway/server.go +90 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/handlers/agent_handler.go +94 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/handlers/approval_handler.go +122 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/handlers/insights_handler.go +37 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/handlers/policy_catalog_handler.go +35 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/handlers/replay_handler.go +61 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/handlers/tool_handler.go +51 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/middleware/auth.go +29 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/middleware/cors.go +60 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/middleware/jwt.go +47 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/middleware/logging.go +35 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/middleware/recovery.go +27 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/middleware/tracing.go +15 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/models/policy.go +38 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/models/request.go +11 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/models/response.go +8 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/policy/evaluator.go +64 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/policy/mapper.go +33 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/policy/opa_client.go +83 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/policycatalog/rules.go +242 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/policycatalog/rules_test.go +80 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/policycatalog/scanner.go +126 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/policycatalog/scanner_test.go +54 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/registry/agent.go +53 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/registry/memory.go +154 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/replay/service.go +187 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/replay/service_test.go +76 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/services/audit_service.go +18 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/services/interceptor_service.go +183 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/services/policy_service.go +23 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/storage/postgres/agents.go +153 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/storage/postgres/approval.go +171 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/storage/postgres/audit.go +156 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/storage/postgres/db.go +62 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/storage/postgres/migrations/001_schema.sql +55 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/storage/postgres/migrations/002_seed_agents.sql +7 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/tracing/context.go +24 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/tracing/trace.go +34 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/utils/errors.go +13 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/utils/response.go +28 -0
- truceptor-0.3.2/acp/bundle/interceptor/internal/utils/validation.go +21 -0
- truceptor-0.3.2/acp/bundle/interceptor/policies/README.md +102 -0
- truceptor-0.3.2/acp/bundle/interceptor/policies/mortgage_application.rego +25 -0
- truceptor-0.3.2/acp/bundle/interceptor/policies/mortgage_underwriting.rego +34 -0
- truceptor-0.3.2/acp/bundle/interceptor/policies/rbac.rego +50 -0
- truceptor-0.3.2/acp/bundle/interceptor/policies/router.rego +30 -0
- truceptor-0.3.2/acp/bundle/interceptor/scripts/generate-jwt-keys.sh +35 -0
- truceptor-0.3.2/acp/bundle/interceptor/scripts/run-local.sh +24 -0
- truceptor-0.3.2/acp/bundle/jwt/public.pem +9 -0
- truceptor-0.3.2/acp/bundle/nginx-dashboard.conf +26 -0
- truceptor-0.3.2/acp/bundle/nginx-gateway.conf +36 -0
- truceptor-0.3.2/acp/bundle/policies/README.md +102 -0
- truceptor-0.3.2/acp/bundle/policies/mortgage_application.rego +25 -0
- truceptor-0.3.2/acp/bundle/policies/mortgage_underwriting.rego +34 -0
- truceptor-0.3.2/acp/bundle/policies/rbac.rego +50 -0
- truceptor-0.3.2/acp/bundle/policies/router.rego +30 -0
- truceptor-0.3.2/acp/bundle/public/index.html +12 -0
- truceptor-0.3.2/acp/cli.py +177 -0
- truceptor-0.3.2/acp/client.py +215 -0
- truceptor-0.3.2/acp/config.py +19 -0
- truceptor-0.3.2/acp/decorators.py +61 -0
- truceptor-0.3.2/acp/exceptions.py +30 -0
- truceptor-0.3.2/acp/policies.py +113 -0
- truceptor-0.3.2/acp/policy-starter/mortgage_application.rego +25 -0
- truceptor-0.3.2/acp/policy-starter/mortgage_underwriting.rego +34 -0
- truceptor-0.3.2/acp/policy-starter/rbac.rego +50 -0
- truceptor-0.3.2/acp/policy-starter/router.rego +30 -0
- truceptor-0.3.2/acp/runtime.py +93 -0
- truceptor-0.3.2/pyproject.toml +56 -0
- truceptor-0.3.2/setup.cfg +4 -0
- truceptor-0.3.2/tests/test_decorator.py +41 -0
- truceptor-0.3.2/truceptor.egg-info/PKG-INFO +401 -0
- truceptor-0.3.2/truceptor.egg-info/SOURCES.txt +110 -0
- truceptor-0.3.2/truceptor.egg-info/dependency_links.txt +1 -0
- truceptor-0.3.2/truceptor.egg-info/entry_points.txt +2 -0
- truceptor-0.3.2/truceptor.egg-info/requires.txt +8 -0
- truceptor-0.3.2/truceptor.egg-info/top_level.txt +1 -0
truceptor-0.3.2/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Raja Datascientist
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
recursive-include acp/bundle *
|
truceptor-0.3.2/PKG-INFO
ADDED
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: truceptor
|
|
3
|
+
Version: 0.3.2
|
|
4
|
+
Summary: Truceptor — trusted intercept for agent tool calls: allow/deny/escalate (does not execute tools).
|
|
5
|
+
Author: SV
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Keywords: ai,agents,governance,policy,opa,control-plane,mcp,audit
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: requests>=2.33.0
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
21
|
+
Requires-Dist: build>=1.0; extra == "dev"
|
|
22
|
+
Requires-Dist: twine>=5.0; extra == "dev"
|
|
23
|
+
Requires-Dist: pip-audit>=2.7; extra == "dev"
|
|
24
|
+
Requires-Dist: bandit>=1.7; extra == "dev"
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
# Truceptor (Python SDK)
|
|
28
|
+
|
|
29
|
+
**Truceptor** — trusted intercept for agent tool calls: preflight allow/deny/escalate; your runtime executes tools after allow.
|
|
30
|
+
|
|
31
|
+
> CLI stays **`acp`** (`acp up`, `acp init`). Install: **`pip install truceptor`**.
|
|
32
|
+
|
|
33
|
+
> **Note:** “ACP” means many things in other industries (medical, political, nonprofit, and more). In this project it always means **ACP — AI Control Plane**, not a generic acronym.
|
|
34
|
+
|
|
35
|
+
**Add governance, approvals, policy enforcement, and execution visibility to AI agents in minutes.**
|
|
36
|
+
|
|
37
|
+
Works with CrewAI, LangGraph, Strands, Google ADK, MCP tools, and custom Python workflows.
|
|
38
|
+
|
|
39
|
+
**Requires:** [Docker Desktop](https://docs.docker.com/get-docker/) (Compose v2).
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Quick start
|
|
44
|
+
|
|
45
|
+
Make sure Docker Desktop is already running before you start ACP.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install truceptor
|
|
49
|
+
acp init # creates starter policies in ~/.acp/policies
|
|
50
|
+
acp up
|
|
51
|
+
acp dashboard # open governance UI
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
| Step | Command |
|
|
55
|
+
|------|---------|
|
|
56
|
+
| Install | `pip install truceptor` |
|
|
57
|
+
| Initialize policies | `acp init` |
|
|
58
|
+
| Start stack | `acp up` |
|
|
59
|
+
| Open UI | `acp dashboard` → http://localhost:3090/dashboard/ |
|
|
60
|
+
| Stop | `acp down` |
|
|
61
|
+
|
|
62
|
+
For a real local integration, the usual sequence is:
|
|
63
|
+
|
|
64
|
+
1. `acp init`
|
|
65
|
+
2. start Docker Desktop
|
|
66
|
+
3. `acp up`
|
|
67
|
+
4. `export ACP_INTERCEPTOR_URL=http://localhost:8080`
|
|
68
|
+
5. `export ACP_BEARER_TOKEN=...`
|
|
69
|
+
6. run your governed agent
|
|
70
|
+
|
|
71
|
+
If Docker is not already running, `acp up` will fail with Docker daemon / compose connection errors.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Why ACP — AI Control Plane?
|
|
76
|
+
|
|
77
|
+
Most agents call tools, APIs, and other agents directly. Teams then scatter rules across Python, workflows, and frameworks:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
if supplier_risk_score > threshold:
|
|
81
|
+
require_human_approval()
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
That becomes inconsistent, hard to audit, easy to bypass, and duplicated everywhere.
|
|
85
|
+
|
|
86
|
+
**ACP — AI Control Plane** centralizes governance **outside** agent code:
|
|
87
|
+
|
|
88
|
+
| Capability | What you get |
|
|
89
|
+
|------------|----------------|
|
|
90
|
+
| **Centralized governance** | One place for rules, not copy-paste per team |
|
|
91
|
+
| **Policy enforcement** | OPA/Rego evaluates every governed call |
|
|
92
|
+
| **Approvals** | Escalate high-risk actions to humans |
|
|
93
|
+
| **A2A governance** | Governed agent-to-agent calls |
|
|
94
|
+
| **A2T governance** | Governed agent-to-tool calls |
|
|
95
|
+
| **Audit & visibility** | Decisions, traces, registry in one dashboard |
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Architecture
|
|
100
|
+
|
|
101
|
+

|
|
102
|
+
|
|
103
|
+
```text
|
|
104
|
+
Agent runtime -> ACP SDK -> Interceptor / Gateway -> OPA / Rego -> allow | deny | escalate -> governed execution
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
ACP sits at the execution boundary:
|
|
108
|
+
|
|
109
|
+
- agent frameworks keep reasoning and orchestration
|
|
110
|
+
- the interceptor validates identity, routes policy, and records audit traces
|
|
111
|
+
- OPA / Rego returns deterministic allow, deny, or escalate decisions
|
|
112
|
+
- only allowed or approved requests reach tools, APIs, MCP servers, or other agents
|
|
113
|
+
|
|
114
|
+
## Request sequence
|
|
115
|
+
|
|
116
|
+

|
|
117
|
+
|
|
118
|
+
Typical governed flow:
|
|
119
|
+
|
|
120
|
+
1. the agent calls a governed function through the ACP SDK
|
|
121
|
+
2. the interceptor validates JWT identity and normalizes the request
|
|
122
|
+
3. OPA / Rego evaluates policy for the tool, action, and claims
|
|
123
|
+
4. ACP records the decision and exposes it in the dashboard
|
|
124
|
+
5. the SDK executes only on `allow`, waits for review on `escalate`, and blocks on `deny`
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Dashboard
|
|
129
|
+
|
|
130
|
+
The **ACP — AI Control Plane** dashboard is a core differentiator: live allow/deny/escalate decisions, approvals, agent registry, and policy catalog. Open **http://localhost:3090/dashboard/** after `acp up`.
|
|
131
|
+
|
|
132
|
+
### Overview & activity
|
|
133
|
+
|
|
134
|
+

|
|
135
|
+
|
|
136
|
+

|
|
137
|
+
|
|
138
|
+
### Decisions & approvals
|
|
139
|
+
|
|
140
|
+

|
|
141
|
+
|
|
142
|
+

|
|
143
|
+
|
|
144
|
+
### Registry & policies
|
|
145
|
+
|
|
146
|
+

|
|
147
|
+
|
|
148
|
+

|
|
149
|
+
|
|
150
|
+

|
|
151
|
+
|
|
152
|
+
### Forensics
|
|
153
|
+
|
|
154
|
+

|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Deployment modes
|
|
159
|
+
|
|
160
|
+
| Mode | How | Best for |
|
|
161
|
+
|------|-----|----------|
|
|
162
|
+
| **Local** | `acp up` via pip + Docker | Demos, dev, quickstart |
|
|
163
|
+
| **SDK** | `@governed_tool` in your agent code | CrewAI, LangGraph, Strands, custom Python |
|
|
164
|
+
| **Gateway** | Single origin on `:3090` (dashboard + API proxy) | Local unified URL; pattern for prod ingress |
|
|
165
|
+
| **Cloud / self-hosted** | Docker Compose, Kubernetes, ECS/EKS on AWS/Azure/GCP | Team or enterprise rollout |
|
|
166
|
+
|
|
167
|
+
**Local endpoints**
|
|
168
|
+
|
|
169
|
+
| URL | Purpose |
|
|
170
|
+
|-----|---------|
|
|
171
|
+
| http://localhost:3090/dashboard/ | Governance dashboard |
|
|
172
|
+
| http://localhost:8080 | Interceptor API (`/tool-call`, `/api/v1/*`) |
|
|
173
|
+
|
|
174
|
+
**Self-hosted (example)**
|
|
175
|
+
|
|
176
|
+
```text
|
|
177
|
+
https://acp.your-company.example
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Example: governed tool
|
|
183
|
+
|
|
184
|
+
Set `ACP_INTERCEPTOR_URL` and `ACP_BEARER_TOKEN` **before** defining a `@governed_tool`.
|
|
185
|
+
|
|
186
|
+
The decorator constructs its ACP client at decoration time, so setting those env vars later inside `main()` is too late.
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
import os
|
|
190
|
+
from acp import governed_tool
|
|
191
|
+
|
|
192
|
+
# Set env vars before decorator evaluation.
|
|
193
|
+
os.environ.setdefault("ACP_INTERCEPTOR_URL", "http://localhost:8080")
|
|
194
|
+
os.environ.setdefault("ACP_BEARER_TOKEN", "<dev-jwt>")
|
|
195
|
+
|
|
196
|
+
@governed_tool(
|
|
197
|
+
agent_id="texas-weather-agent",
|
|
198
|
+
tool="weather_api",
|
|
199
|
+
action="read_weather",
|
|
200
|
+
)
|
|
201
|
+
def get_texas_weather(city: str):
|
|
202
|
+
return {"city": city, "status": "pending_review"}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
The **AI Control Plane** intercepts the call, evaluates policy, then allows, denies, or escalates.
|
|
206
|
+
|
|
207
|
+
`tool="weather_api"` is the governed ACP tool id. It does **not** have to match the Python function name (`get_texas_weather`). ACP policy keys on `tool`, not the Python symbol name.
|
|
208
|
+
|
|
209
|
+
The JWT `agent_id` claim must match `agent_id="texas-weather-agent"` in `@governed_tool(...)`.
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Example: policy (Rego)
|
|
214
|
+
|
|
215
|
+
```rego
|
|
216
|
+
package acp.policy
|
|
217
|
+
|
|
218
|
+
allow {
|
|
219
|
+
input.identity.role == "supply-chain-manager"
|
|
220
|
+
input.action.tool == "supplier_approval"
|
|
221
|
+
input.risk_score < 70
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Edit policies in `~/.acp/policies/` after `acp init`.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Adding a new governed tool
|
|
230
|
+
|
|
231
|
+
`acp init` creates starter policy files in `~/.acp/policies/`, but you still need to wire new tools into policy yourself.
|
|
232
|
+
|
|
233
|
+
For a brand-new governed tool, update all of these:
|
|
234
|
+
|
|
235
|
+
1. choose an ACP tool id, for example `weather_api`
|
|
236
|
+
2. add tool-to-role mapping in `~/.acp/policies/rbac.rego`
|
|
237
|
+
3. route the tool in `~/.acp/policies/router.rego`
|
|
238
|
+
4. add or reuse a domain policy file such as `weather.rego`
|
|
239
|
+
5. mint and export `ACP_BEARER_TOKEN`
|
|
240
|
+
6. make sure the JWT `agent_id` claim matches `@governed_tool(agent_id=...)`
|
|
241
|
+
7. run the agent
|
|
242
|
+
|
|
243
|
+
Two valid patterns:
|
|
244
|
+
|
|
245
|
+
### Pattern 1: reuse an ACP tool bucket
|
|
246
|
+
|
|
247
|
+
Use one ACP tool id for multiple Python functions in the same policy domain.
|
|
248
|
+
|
|
249
|
+
```python
|
|
250
|
+
@governed_tool(
|
|
251
|
+
agent_id="texas-weather-agent",
|
|
252
|
+
tool="weather_api",
|
|
253
|
+
action="read_weather",
|
|
254
|
+
)
|
|
255
|
+
def get_texas_weather(city: str):
|
|
256
|
+
...
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
`~/.acp/policies/rbac.rego`
|
|
260
|
+
|
|
261
|
+
```rego
|
|
262
|
+
"weather_api": ["weather"],
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
`~/.acp/policies/router.rego`
|
|
266
|
+
|
|
267
|
+
```rego
|
|
268
|
+
decision = weather.decision {
|
|
269
|
+
input.tool == "weather_api"
|
|
270
|
+
rbac.decision.decision == "allow"
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
`~/.acp/policies/weather.rego`
|
|
275
|
+
|
|
276
|
+
```rego
|
|
277
|
+
package acp.weather
|
|
278
|
+
|
|
279
|
+
default decision = {
|
|
280
|
+
"decision": "allow",
|
|
281
|
+
"reason": "weather_action_allowed",
|
|
282
|
+
"policy": "acp/weather",
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
decision = {
|
|
286
|
+
"decision": "deny",
|
|
287
|
+
"reason": "weather_action_not_permitted",
|
|
288
|
+
"policy": "acp/weather",
|
|
289
|
+
} {
|
|
290
|
+
not input.action == "read_weather"
|
|
291
|
+
not input.action == "read_weather_batch"
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Pattern 2: add a brand-new ACP tool id
|
|
296
|
+
|
|
297
|
+
If you want policy to key directly on a new id such as `get_texas_weather`, add that id to both `rbac.rego` and `router.rego`, then route it to the right domain policy file.
|
|
298
|
+
|
|
299
|
+
If your starter `router.rego` or `rbac.rego` references a tool id, make sure the corresponding domain policy file also exists.
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## Local JWT dev example
|
|
304
|
+
|
|
305
|
+
Local governed `/tool-call` requests require a bearer token when JWT auth is enabled. `ACP_INTERCEPTOR_URL` alone is not enough.
|
|
306
|
+
|
|
307
|
+
Set:
|
|
308
|
+
|
|
309
|
+
- `ACP_INTERCEPTOR_URL=http://localhost:8080`
|
|
310
|
+
- `ACP_BEARER_TOKEN=<signed-jwt>`
|
|
311
|
+
|
|
312
|
+
If `ACP_BEARER_TOKEN` is missing, governed calls may fail with `401 Unauthorized` / `missing bearer token`.
|
|
313
|
+
|
|
314
|
+
One dev-friendly way to mint a token is:
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
python -m pip install pyjwt cryptography
|
|
318
|
+
|
|
319
|
+
export ACP_BEARER_TOKEN="$(
|
|
320
|
+
python - <<'PY'
|
|
321
|
+
from pathlib import Path
|
|
322
|
+
import time
|
|
323
|
+
import jwt
|
|
324
|
+
|
|
325
|
+
private_key = (Path.home() / ".acp" / "jwt" / "private.pem").read_text()
|
|
326
|
+
token = jwt.encode(
|
|
327
|
+
{
|
|
328
|
+
"sub": "agent:texas-weather-agent",
|
|
329
|
+
"agent_id": "texas-weather-agent",
|
|
330
|
+
"roles": ["weather"],
|
|
331
|
+
"iss": "acp-dev",
|
|
332
|
+
"aud": "acp-interceptor",
|
|
333
|
+
"exp": int(time.time()) + 3600,
|
|
334
|
+
},
|
|
335
|
+
private_key,
|
|
336
|
+
algorithm="RS256",
|
|
337
|
+
)
|
|
338
|
+
print(token)
|
|
339
|
+
PY
|
|
340
|
+
)"
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Use these claims for local development:
|
|
344
|
+
|
|
345
|
+
- `sub=agent:texas-weather-agent`
|
|
346
|
+
- `agent_id=texas-weather-agent`
|
|
347
|
+
- `roles=["weather"]`
|
|
348
|
+
- `iss=acp-dev`
|
|
349
|
+
- `aud=acp-interceptor`
|
|
350
|
+
|
|
351
|
+
`agent_id` in the JWT must match the `agent_id` passed to `@governed_tool(...)`.
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## Example: governance flow
|
|
356
|
+
|
|
357
|
+
```text
|
|
358
|
+
Supply Chain Agent
|
|
359
|
+
→ ACP — AI Control Plane validates identity (JWT)
|
|
360
|
+
→ OPA evaluates policy
|
|
361
|
+
→ Decision: ESCALATE
|
|
362
|
+
→ Human approves in dashboard
|
|
363
|
+
→ Execution resumes
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## What the AI Control Plane provides
|
|
369
|
+
|
|
370
|
+
- **Policy enforcement** — OPA/Rego (Cedar on roadmap)
|
|
371
|
+
- **Identity** — JWT from Okta, Auth0, Keycloak, or your IdP
|
|
372
|
+
- **Approvals** — human-in-the-loop for risky actions
|
|
373
|
+
- **Observability** — dashboard for decisions, traces, agents, tools
|
|
374
|
+
- **Agent registry** — lightweight catalog of agents and capabilities
|
|
375
|
+
- **Framework-friendly** — keep CrewAI / LangGraph / Strands for reasoning; govern execution here
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
## Philosophy
|
|
380
|
+
|
|
381
|
+
Orchestration frameworks handle **reasoning, planning, and workflows**.
|
|
382
|
+
|
|
383
|
+
**ACP — AI Control Plane** handles **governance, trust, approvals, policy, and auditability**.
|
|
384
|
+
|
|
385
|
+
Reasoning stays autonomous. Execution stays governed.
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## Roadmap
|
|
390
|
+
|
|
391
|
+
- MCP/A2A governance intercept (decision-only, no execution)
|
|
392
|
+
- MCP-native governance
|
|
393
|
+
- Policy studio and replay
|
|
394
|
+
- Enterprise topology views
|
|
395
|
+
- Multi-cloud deployment templates
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
## License
|
|
400
|
+
|
|
401
|
+
MIT License
|