Skip to content

Commit 4bec022

Browse files
committed
user manual
1 parent 347f224 commit 4bec022

1 file changed

Lines changed: 323 additions & 0 deletions

File tree

Lines changed: 323 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
1+
# Predicate Authority User Manual
2+
3+
This guide explains how to use `predicate-authority` in real projects with
4+
practical examples. It is written for application developers and platform
5+
operators who want deterministic, pre-execution authorization for AI agents.
6+
7+
---
8+
9+
## What is `predicate-authority`?
10+
11+
`predicate-authority` is an authorization layer for AI agents.
12+
13+
It checks risky actions **before execution** (fail-closed by default), issues
14+
short-lived mandates for allowed actions, and records proof events for audit.
15+
16+
Core use cases:
17+
18+
- protect outbound API calls,
19+
- protect tool invocation (MCP/function calls),
20+
- enforce policy invariants using state and verification evidence,
21+
- centralize revocation and operational controls through a sidecar.
22+
23+
---
24+
25+
## Package overview
26+
27+
- `predicate_contracts`: shared typed contracts and protocols.
28+
- `predicate_authority`: policy engine, guard, sidecar, identity bridge,
29+
revocation, proof ledger.
30+
- `predicate-authorityd`: optional local sidecar daemon (CLI service).
31+
32+
---
33+
34+
## Install
35+
36+
```bash
37+
pip install predicate-contracts predicate-authority
38+
```
39+
40+
For local development from source:
41+
42+
```bash
43+
cd /path/to/AgentIdentity
44+
pip install -e ./predicate_contracts
45+
pip install -e ./predicate_authority
46+
```
47+
48+
---
49+
50+
## Fastest local validation path (Day 1)
51+
52+
Use this path if you want fast feedback with minimal setup.
53+
54+
You do **not** need:
55+
56+
- Entra ID / enterprise IdP setup,
57+
- two browser agents,
58+
- hosted control plane.
59+
60+
### Step 1: run one local authorize/deny script
61+
62+
- Use in-process `ActionGuard` with a tiny local policy.
63+
- Build one allowed request and one denied request.
64+
- Confirm deny reason is deterministic.
65+
66+
### Step 2: simulate delegation with two Python scripts
67+
68+
- Script A (root) requests a mandate with limited delegation depth.
69+
- Script B (worker) uses the received token and attempts delegated action.
70+
- Validate expected behavior for:
71+
- valid delegation,
72+
- over-depth delegation (must fail),
73+
- revoked root/intent (must fail).
74+
75+
### Step 3: optional sidecar smoke test
76+
77+
- Start `predicate-authorityd` in local mode.
78+
- Call `/status`, `/ledger/flush-now`, and `/ledger/dead-letter`.
79+
- Confirm operations safety endpoints work before enterprise integration.
80+
81+
When this passes, add enterprise IdP (OIDC/Entra) and real web-agent E2E flows.
82+
83+
---
84+
85+
## Mental model
86+
87+
1. Build an `ActionRequest` from current agent context.
88+
2. Call `ActionGuard.authorize(request)` (or sidecar equivalent).
89+
3. If allowed, execute action (with mandate attached if needed).
90+
4. If denied, stop action and handle deny reason.
91+
5. Emit/store proof events for governance.
92+
93+
---
94+
95+
## Quick start (in-process guard)
96+
97+
```python
98+
from predicate_authority import ActionGuard, InMemoryProofLedger, LocalMandateSigner, PolicyEngine
99+
from predicate_contracts import (
100+
ActionRequest,
101+
ActionSpec,
102+
PolicyEffect,
103+
PolicyRule,
104+
PrincipalRef,
105+
StateEvidence,
106+
VerificationEvidence,
107+
VerificationSignal,
108+
VerificationStatus,
109+
)
110+
111+
rules = (
112+
PolicyRule(
113+
name="allow-orders-create",
114+
effect=PolicyEffect.ALLOW,
115+
principals=("agent:checkout",),
116+
actions=("http.post",),
117+
resources=("https://api.vendor.com/orders",),
118+
required_labels=("on_checkout_page",),
119+
),
120+
)
121+
122+
guard = ActionGuard(
123+
policy_engine=PolicyEngine(rules=rules),
124+
mandate_signer=LocalMandateSigner(secret_key="replace-with-strong-secret"),
125+
proof_ledger=InMemoryProofLedger(),
126+
)
127+
128+
request = ActionRequest(
129+
principal=PrincipalRef(principal_id="agent:checkout", tenant_id="tenant-a"),
130+
action_spec=ActionSpec(
131+
action="http.post",
132+
resource="https://api.vendor.com/orders",
133+
intent="submit customer order",
134+
),
135+
state_evidence=StateEvidence(source="sdk-python", state_hash="sha256:abc123"),
136+
verification_evidence=VerificationEvidence(
137+
signals=(
138+
VerificationSignal(
139+
label="on_checkout_page",
140+
status=VerificationStatus.PASSED,
141+
required=True,
142+
),
143+
)
144+
),
145+
)
146+
147+
decision = guard.authorize(request)
148+
if not decision.allowed:
149+
raise RuntimeError(f"Denied: {decision.reason.value}")
150+
151+
print("Allowed. mandate_id=", decision.mandate.claims.mandate_id if decision.mandate else None)
152+
```
153+
154+
---
155+
156+
## Policy basics
157+
158+
A policy rule matches:
159+
160+
- principal (`agent:*`, `agent:checkout`, etc.),
161+
- action (`http.post`, `tool.execute`, `browser.click`),
162+
- resource (`https://...`, `mcp://...`, etc.),
163+
- optional required verification labels.
164+
165+
If no allow rule matches, behavior is deny (`NO_MATCHING_POLICY`).
166+
167+
Common deny reasons:
168+
169+
- `NO_MATCHING_POLICY`
170+
- `EXPLICIT_DENY`
171+
- `MISSING_REQUIRED_VERIFICATION`
172+
- `INVALID_MANDATE`
173+
174+
---
175+
176+
## Using the sidecar (`predicate-authorityd`)
177+
178+
Start local sidecar with file policy:
179+
180+
```bash
181+
PYTHONPATH=. predicate-authorityd \
182+
--host 127.0.0.1 \
183+
--port 8787 \
184+
--mode local_only \
185+
--policy-file examples/authorityd/policy.json
186+
```
187+
188+
Health and status:
189+
190+
```bash
191+
curl -s http://127.0.0.1:8787/health | jq
192+
curl -s http://127.0.0.1:8787/status | jq
193+
```
194+
195+
---
196+
197+
## Identity modes
198+
199+
`predicate-authorityd` supports multiple identity bridge modes:
200+
201+
- `local` (default): local deterministic bridge,
202+
- `local-idp`: local IdP-style signed token mode (offline/dev/air-gapped),
203+
- `oidc`: enterprise OIDC bridge,
204+
- `entra`: Microsoft Entra bridge.
205+
206+
Example (`local-idp`):
207+
208+
```bash
209+
export LOCAL_IDP_SIGNING_KEY="replace-with-strong-secret"
210+
predicate-authorityd \
211+
--host 127.0.0.1 \
212+
--port 8787 \
213+
--mode local_only \
214+
--policy-file examples/authorityd/policy.json \
215+
--identity-mode local-idp \
216+
--local-idp-issuer "http://localhost/predicate-local-idp" \
217+
--local-idp-audience "api://predicate-authority"
218+
```
219+
220+
---
221+
222+
## Local identity registry + flush queue
223+
224+
Enable ephemeral task identity registry and local ledger queue:
225+
226+
```bash
227+
PYTHONPATH=. predicate-authorityd \
228+
--host 127.0.0.1 \
229+
--port 8787 \
230+
--mode local_only \
231+
--policy-file examples/authorityd/policy.json \
232+
--local-identity-enabled \
233+
--local-identity-registry-file ./.predicate-authorityd/local-identities.json \
234+
--local-identity-default-ttl-s 900 \
235+
--flush-worker-enabled \
236+
--flush-worker-interval-s 2.0 \
237+
--flush-worker-max-batch-size 50 \
238+
--flush-worker-dead-letter-max-attempts 5
239+
```
240+
241+
Useful endpoints:
242+
243+
- `POST /identity/task`
244+
- `GET /identity/list`
245+
- `POST /identity/revoke`
246+
- `GET /ledger/flush-queue`
247+
- `POST /ledger/flush-now`
248+
- `GET /ledger/dead-letter`
249+
- `POST /ledger/requeue`
250+
251+
---
252+
253+
## Operations safety patterns
254+
255+
Recommended production defaults:
256+
257+
- keep fail-closed for protected actions,
258+
- use dead-letter threshold to quarantine persistent failures,
259+
- expose `/status` metrics to monitoring,
260+
- provide runbooks for manual flush and dead-letter requeue.
261+
262+
Example manual recovery:
263+
264+
```bash
265+
# trigger immediate flush
266+
curl -s -X POST http://127.0.0.1:8787/ledger/flush-now \
267+
-H "Content-Type: application/json" \
268+
-d '{"max_items":50}' | jq
269+
270+
# inspect quarantined items
271+
curl -s http://127.0.0.1:8787/ledger/dead-letter | jq
272+
273+
# requeue a quarantined item
274+
curl -s -X POST http://127.0.0.1:8787/ledger/requeue \
275+
-H "Content-Type: application/json" \
276+
-d '{"queue_item_id":"q_abc123"}' | jq
277+
```
278+
279+
---
280+
281+
## `sdk-python` integration example (boundary adapter flow)
282+
283+
If your web agent uses `sdk-python`, build shared contract evidence before
284+
calling authority:
285+
286+
```python
287+
from predicate.agent_runtime import AgentRuntime
288+
289+
# after snapshot + assertions
290+
request = runtime.build_authority_action_request(
291+
principal_id="agent:web-checkout",
292+
action="browser.click",
293+
resource="https://example.com/checkout",
294+
intent="click submit order",
295+
tenant_id="tenant-a",
296+
)
297+
298+
# send request to your authority hook/client
299+
decision = my_authorizer(request)
300+
if not decision.allowed:
301+
raise RuntimeError("Denied by authority")
302+
```
303+
304+
---
305+
306+
## Troubleshooting
307+
308+
- Denied with `MISSING_REQUIRED_VERIFICATION`:
309+
- ensure required labels are present and `PASSED` in evidence.
310+
- Denied with `NO_MATCHING_POLICY`:
311+
- verify principal/action/resource match patterns in active policy.
312+
- Token exchange errors in connected mode:
313+
- verify identity mode config and credential/refresh-token setup.
314+
- Queue not draining:
315+
- check `/status` flush counters and control-plane connectivity.
316+
317+
---
318+
319+
## Where to go next
320+
321+
- Operations guide: `docs/authorityd-operations.md`
322+
- Architecture proposal: `docs/predicate_authority_docs/better-sdk-opportunity-proposal.md`
323+
- Governance sign-off tracker: `docs/predicate_authority_docs/governance-signoff-tracker.md`

0 commit comments

Comments
 (0)