safety-protocol 0.3.0__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.
- safety_protocol-0.3.0/LICENSE +21 -0
- safety_protocol-0.3.0/MANIFEST.in +23 -0
- safety_protocol-0.3.0/PKG-INFO +217 -0
- safety_protocol-0.3.0/README.md +179 -0
- safety_protocol-0.3.0/examples/agent_client.py +70 -0
- safety_protocol-0.3.0/examples/agent_insurance_sim.py +886 -0
- safety_protocol-0.3.0/examples/claims_demo_verified.py +180 -0
- safety_protocol-0.3.0/examples/cli.py +20 -0
- safety_protocol-0.3.0/examples/generate_testnet_wallets.py +88 -0
- safety_protocol-0.3.0/examples/guard_config.json +59 -0
- safety_protocol-0.3.0/examples/live_settlement_test.py +237 -0
- safety_protocol-0.3.0/examples/llm_agent.py +492 -0
- safety_protocol-0.3.0/examples/llm_agent_real.py +308 -0
- safety_protocol-0.3.0/examples/mock_merchant.py +128 -0
- safety_protocol-0.3.0/examples/reference_deployment.py +394 -0
- safety_protocol-0.3.0/examples/safe_spend_demo.py +141 -0
- safety_protocol-0.3.0/examples/salesforce/guard_config.salesforce.json +61 -0
- safety_protocol-0.3.0/examples/scope_lint_demo.py +94 -0
- safety_protocol-0.3.0/examples/scope_test.py +213 -0
- safety_protocol-0.3.0/examples/settlement_demo.py +125 -0
- safety_protocol-0.3.0/pyproject.toml +85 -0
- safety_protocol-0.3.0/setup.cfg +4 -0
- safety_protocol-0.3.0/src/safety_protocol/__init__.py +201 -0
- safety_protocol-0.3.0/src/safety_protocol/cli.py +132 -0
- safety_protocol-0.3.0/src/safety_protocol/core.py +424 -0
- safety_protocol-0.3.0/src/safety_protocol/data/guard_config.json +59 -0
- safety_protocol-0.3.0/src/safety_protocol/deployment.py +384 -0
- safety_protocol-0.3.0/src/safety_protocol/guard_service.py +241 -0
- safety_protocol-0.3.0/src/safety_protocol/insurance.py +221 -0
- safety_protocol-0.3.0/src/safety_protocol/onchain.py +271 -0
- safety_protocol-0.3.0/src/safety_protocol/onchain_audit.py +346 -0
- safety_protocol-0.3.0/src/safety_protocol/onchain_payment_verifier.py +174 -0
- safety_protocol-0.3.0/src/safety_protocol/payments.py +380 -0
- safety_protocol-0.3.0/src/safety_protocol/protocol.py +547 -0
- safety_protocol-0.3.0/src/safety_protocol/real_wallet.py +189 -0
- safety_protocol-0.3.0/src/safety_protocol/scope_linter.py +191 -0
- safety_protocol-0.3.0/src/safety_protocol.egg-info/SOURCES.txt +38 -0
- safety_protocol-0.3.0/tests/test_cli.py +74 -0
- safety_protocol-0.3.0/tests/test_insurance.py +37 -0
- safety_protocol-0.3.0/tests/test_packaging.py +36 -0
- safety_protocol-0.3.0/tests/test_sovereign_agent.py +31 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Michael / TheDub-lab
|
|
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,23 @@
|
|
|
1
|
+
include LICENSE
|
|
2
|
+
include README.md
|
|
3
|
+
include pyproject.toml
|
|
4
|
+
|
|
5
|
+
# Packaged default config (also shipped as wheel package-data)
|
|
6
|
+
recursive-include src/safety_protocol/data *.json
|
|
7
|
+
|
|
8
|
+
# Worked examples (developer-facing), not marketing assets
|
|
9
|
+
recursive-include examples *.py *.json
|
|
10
|
+
|
|
11
|
+
# Keep the source distribution lean: no marketing/promo assets, no root demo,
|
|
12
|
+
# no local state or build cruft.
|
|
13
|
+
exclude carrier_deck.html
|
|
14
|
+
exclude examples/loss_curve.png
|
|
15
|
+
exclude examples/loss_curve.svg
|
|
16
|
+
exclude sovereign_agent.py
|
|
17
|
+
exclude agent_capabilities.py
|
|
18
|
+
exclude agent_memory.json
|
|
19
|
+
exclude testnet_wallets.json
|
|
20
|
+
prune src/safety_protocol/__pycache__
|
|
21
|
+
prune src/safety_protocol.egg-info
|
|
22
|
+
global-exclude __pycache__
|
|
23
|
+
global-exclude *.py[cod]
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: safety-protocol
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Safety protocol framework for LLM agents — binding, scope, enforcement, monitoring, approval, audit, killswitch
|
|
5
|
+
Author-email: Michael <michael@example.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/TheDub-lab/agentcover-sovereign
|
|
8
|
+
Project-URL: Repository, https://github.com/TheDub-lab/agentcover-sovereign
|
|
9
|
+
Project-URL: Issues, https://github.com/TheDub-lab/agentcover-sovereign/issues
|
|
10
|
+
Keywords: ai-agents,agent-safety,agent-governance,authorization,llm,guardrails,scope,audit,killswitch
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Classifier: Topic :: Security
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Provides-Extra: onchain
|
|
24
|
+
Requires-Dist: requests>=2.31; extra == "onchain"
|
|
25
|
+
Provides-Extra: crypto
|
|
26
|
+
Requires-Dist: eth-account>=0.11; extra == "crypto"
|
|
27
|
+
Provides-Extra: demo
|
|
28
|
+
Requires-Dist: openai>=1.30; extra == "demo"
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
31
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
32
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
33
|
+
Requires-Dist: twine>=5.0; extra == "dev"
|
|
34
|
+
Provides-Extra: all
|
|
35
|
+
Requires-Dist: requests>=2.31; extra == "all"
|
|
36
|
+
Requires-Dist: eth-account>=0.11; extra == "all"
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
# safety-protocol
|
|
40
|
+
|
|
41
|
+
[](https://github.com/TheDub-lab/agentcover-sovereign/actions/workflows/ci.yml)
|
|
42
|
+
[](https://pypi.org/project/safety-protocol/)
|
|
43
|
+
[](https://pypi.org/project/safety-protocol/)
|
|
44
|
+
[](LICENSE)
|
|
45
|
+
|
|
46
|
+
Enforceable governance for LLM agents. Instead of hoping the model behaves,
|
|
47
|
+
every action passes through infrastructure that enforces **binding, closed
|
|
48
|
+
vocabulary, least-privilege scope, spend caps, approval gates, a hash-chained
|
|
49
|
+
audit trail, and a kill switch**. Deny-by-default: an action is permitted only
|
|
50
|
+
if a rule explicitly allows it.
|
|
51
|
+
|
|
52
|
+
The agent proposes; the protocol decides. The agent cannot talk its way around
|
|
53
|
+
it, because the check is not a prompt instruction.
|
|
54
|
+
|
|
55
|
+
## Install
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install safety-protocol
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Zero runtime dependencies — the guard, scope linter, audit trail and reference
|
|
62
|
+
deployment are stdlib. Optional integrations are extras:
|
|
63
|
+
|
|
64
|
+
| Extra | Adds |
|
|
65
|
+
| --------- | ----------------------------------------------------------- |
|
|
66
|
+
| `onchain` | `requests` — verify a settled payment against a JSON-RPC node |
|
|
67
|
+
| `crypto` | `eth-account` — real EIP-3009 / USDC settlement signing |
|
|
68
|
+
| `demo` | `openai` — the repo-root Nebius/Nemotron demo agent |
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install "safety-protocol[onchain,crypto]"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Quickstart (library)
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from safety_protocol import SafetyProtocol, BoundAgent, ScopeRule
|
|
78
|
+
|
|
79
|
+
protocol = SafetyProtocol(
|
|
80
|
+
agent_id="agent-001",
|
|
81
|
+
user_id="alice",
|
|
82
|
+
scope_rules=[
|
|
83
|
+
ScopeRule(
|
|
84
|
+
action_type="api_call",
|
|
85
|
+
allowed_targets=["https://api.example.com/v1/search"],
|
|
86
|
+
match="exact",
|
|
87
|
+
methods=["POST"],
|
|
88
|
+
param_schema={
|
|
89
|
+
"required": ["query"],
|
|
90
|
+
"properties": {"query": {"type": "string", "maximum": 200}},
|
|
91
|
+
"additional_properties": False,
|
|
92
|
+
},
|
|
93
|
+
forbidden_targets=["admin", "billing"],
|
|
94
|
+
max_cost=1.00,
|
|
95
|
+
),
|
|
96
|
+
],
|
|
97
|
+
budget_limit=50.0,
|
|
98
|
+
approval_threshold_cost=10.0,
|
|
99
|
+
allowed_action_types=["api_call"],
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
agent = BoundAgent(agent_id="agent-001", user_id="alice", safety_protocol=protocol)
|
|
103
|
+
|
|
104
|
+
result = agent.propose_action(
|
|
105
|
+
action_type="api_call",
|
|
106
|
+
target="https://api.example.com/v1/search",
|
|
107
|
+
params={"query": "test"},
|
|
108
|
+
estimated_cost=2.50,
|
|
109
|
+
)
|
|
110
|
+
print(result.outcome) # ActionOutcome.ALLOWED
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## The guard (CLI + HTTP)
|
|
114
|
+
|
|
115
|
+
Give the guard a **user-controlled** config; it lints the rules before going
|
|
116
|
+
live and **fails closed** — a config that is too broad refuses to start. The
|
|
117
|
+
agent only ever sends intents; it can never widen its own scope.
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
safety-guard init --out guard_config.json # write a default config
|
|
121
|
+
safety-guard lint --config guard_config.json # exit 1 if too broad
|
|
122
|
+
safety-guard check --config guard_config.json \
|
|
123
|
+
--action api_call --target https://api.research.example/v1/search \
|
|
124
|
+
--method POST --params '{"query":"hi"}'
|
|
125
|
+
safety-guard pay --config guard_config.json \
|
|
126
|
+
--recipient 0xMerchant1111111111111111111111111111111 --usd 0.10
|
|
127
|
+
safety-guard serve --config guard_config.json # HTTP on 127.0.0.1:8080
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The HTTP surface (any agent, any language):
|
|
131
|
+
|
|
132
|
+
| Method | Path | Body |
|
|
133
|
+
| ------ | -------------- | ----------------------------------------------- |
|
|
134
|
+
| POST | `/guard` | `{action_type, target, method?, params?, cost?}` |
|
|
135
|
+
| POST | `/pay` | `{recipient, usd, resource?}` |
|
|
136
|
+
| POST | `/approve` | `{token, approved, approver}` |
|
|
137
|
+
| POST | `/killswitch` | `{reason}` |
|
|
138
|
+
| GET | `/audit` | — (immutable decision log) |
|
|
139
|
+
| GET | `/health` | — (status + lint summary) |
|
|
140
|
+
|
|
141
|
+
Equivalent module entry point: `python -m safety_protocol.guard_service --config guard_config.json`.
|
|
142
|
+
|
|
143
|
+
## Config reference
|
|
144
|
+
|
|
145
|
+
```jsonc
|
|
146
|
+
{
|
|
147
|
+
"agent_id": "guard-agent",
|
|
148
|
+
"user_id": "alice",
|
|
149
|
+
"budget_limit": 20.0, // global session cap (null = none)
|
|
150
|
+
"approval_threshold_cost": 2.0, // actions >= this need human sign-off
|
|
151
|
+
"allowed_action_types": ["api_call", "payment"], // closed verb vocabulary
|
|
152
|
+
"scope_rules": [
|
|
153
|
+
{
|
|
154
|
+
"action_type": "api_call",
|
|
155
|
+
"allowed_targets": ["https://api.research.example/v1/search"], // allowlist
|
|
156
|
+
"match": "exact", // exact | prefix | glob | regex
|
|
157
|
+
"methods": ["POST"], // transport verbs permitted
|
|
158
|
+
"param_schema": { // params MUST satisfy this
|
|
159
|
+
"required": ["query"],
|
|
160
|
+
"properties": {"query": {"type": "string", "maximum": 200}},
|
|
161
|
+
"additional_properties": false
|
|
162
|
+
},
|
|
163
|
+
"forbidden_targets": ["admin", "billing"],
|
|
164
|
+
"forbid_match": "token", // token | substring
|
|
165
|
+
"max_cost": 1.00, // per-rule cap (tightest wins)
|
|
166
|
+
"requires_approval": false
|
|
167
|
+
}
|
|
168
|
+
]
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Every dimension is enforced. Leaving any of them broad (a wildcard prefix, an
|
|
173
|
+
unbound method, an unvalidated param) is what makes the other controls
|
|
174
|
+
decorative — the `safety-guard lint` command exists to catch exactly that
|
|
175
|
+
before deploy.
|
|
176
|
+
|
|
177
|
+
## Architecture
|
|
178
|
+
|
|
179
|
+
| Layer | What it is | Status |
|
|
180
|
+
| ----- | ---------- | ------ |
|
|
181
|
+
| **1. Enforcement** | binding, scope, budget, approval, monitor, audit, killswitch | production-usable |
|
|
182
|
+
| **2. On-chain anchors** | SBT-style binding + on-chain audit of key events | **simulated** (in-memory, same interface as a real chain) |
|
|
183
|
+
| **3. Insurance** | claims evidence, underwriter reports | interface / reference |
|
|
184
|
+
|
|
185
|
+
> **The on-chain layer is simulated.** It is not third-party verifiable until a
|
|
186
|
+
> real contract is deployed. The library discloses this in every binding proof
|
|
187
|
+
> (`on_chain_backend: "simulated_in_memory"`). Use ERC-5192 SBT or ERC-8004 on a
|
|
188
|
+
> real chain in production.
|
|
189
|
+
|
|
190
|
+
`ReferenceDeployment` wires all three layers together; the layers are
|
|
191
|
+
composable and each adds value on its own.
|
|
192
|
+
|
|
193
|
+
## Development
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
pip install -e ".[dev]"
|
|
197
|
+
python -m pytest
|
|
198
|
+
ruff check
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The repo-root files (`sovereign_agent.py`, `agent_capabilities.py`) are a
|
|
202
|
+
standalone demo agent and are **not** part of the package:
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
pip install -e ".[demo]"
|
|
206
|
+
python sovereign_agent.py --offline # no API key needed; same gate logic
|
|
207
|
+
python sovereign_agent.py # live via NEBIUS_API_KEY
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Origin
|
|
211
|
+
|
|
212
|
+
Originally built for the Nebius x NVIDIA Global AI Hackathon (Track: Personal
|
|
213
|
+
AI), then hardened into a general enforcement library.
|
|
214
|
+
|
|
215
|
+
## License
|
|
216
|
+
|
|
217
|
+
MIT. See [`LICENSE`](LICENSE).
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# safety-protocol
|
|
2
|
+
|
|
3
|
+
[](https://github.com/TheDub-lab/agentcover-sovereign/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/safety-protocol/)
|
|
5
|
+
[](https://pypi.org/project/safety-protocol/)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
Enforceable governance for LLM agents. Instead of hoping the model behaves,
|
|
9
|
+
every action passes through infrastructure that enforces **binding, closed
|
|
10
|
+
vocabulary, least-privilege scope, spend caps, approval gates, a hash-chained
|
|
11
|
+
audit trail, and a kill switch**. Deny-by-default: an action is permitted only
|
|
12
|
+
if a rule explicitly allows it.
|
|
13
|
+
|
|
14
|
+
The agent proposes; the protocol decides. The agent cannot talk its way around
|
|
15
|
+
it, because the check is not a prompt instruction.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install safety-protocol
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Zero runtime dependencies — the guard, scope linter, audit trail and reference
|
|
24
|
+
deployment are stdlib. Optional integrations are extras:
|
|
25
|
+
|
|
26
|
+
| Extra | Adds |
|
|
27
|
+
| --------- | ----------------------------------------------------------- |
|
|
28
|
+
| `onchain` | `requests` — verify a settled payment against a JSON-RPC node |
|
|
29
|
+
| `crypto` | `eth-account` — real EIP-3009 / USDC settlement signing |
|
|
30
|
+
| `demo` | `openai` — the repo-root Nebius/Nemotron demo agent |
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install "safety-protocol[onchain,crypto]"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Quickstart (library)
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from safety_protocol import SafetyProtocol, BoundAgent, ScopeRule
|
|
40
|
+
|
|
41
|
+
protocol = SafetyProtocol(
|
|
42
|
+
agent_id="agent-001",
|
|
43
|
+
user_id="alice",
|
|
44
|
+
scope_rules=[
|
|
45
|
+
ScopeRule(
|
|
46
|
+
action_type="api_call",
|
|
47
|
+
allowed_targets=["https://api.example.com/v1/search"],
|
|
48
|
+
match="exact",
|
|
49
|
+
methods=["POST"],
|
|
50
|
+
param_schema={
|
|
51
|
+
"required": ["query"],
|
|
52
|
+
"properties": {"query": {"type": "string", "maximum": 200}},
|
|
53
|
+
"additional_properties": False,
|
|
54
|
+
},
|
|
55
|
+
forbidden_targets=["admin", "billing"],
|
|
56
|
+
max_cost=1.00,
|
|
57
|
+
),
|
|
58
|
+
],
|
|
59
|
+
budget_limit=50.0,
|
|
60
|
+
approval_threshold_cost=10.0,
|
|
61
|
+
allowed_action_types=["api_call"],
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
agent = BoundAgent(agent_id="agent-001", user_id="alice", safety_protocol=protocol)
|
|
65
|
+
|
|
66
|
+
result = agent.propose_action(
|
|
67
|
+
action_type="api_call",
|
|
68
|
+
target="https://api.example.com/v1/search",
|
|
69
|
+
params={"query": "test"},
|
|
70
|
+
estimated_cost=2.50,
|
|
71
|
+
)
|
|
72
|
+
print(result.outcome) # ActionOutcome.ALLOWED
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## The guard (CLI + HTTP)
|
|
76
|
+
|
|
77
|
+
Give the guard a **user-controlled** config; it lints the rules before going
|
|
78
|
+
live and **fails closed** — a config that is too broad refuses to start. The
|
|
79
|
+
agent only ever sends intents; it can never widen its own scope.
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
safety-guard init --out guard_config.json # write a default config
|
|
83
|
+
safety-guard lint --config guard_config.json # exit 1 if too broad
|
|
84
|
+
safety-guard check --config guard_config.json \
|
|
85
|
+
--action api_call --target https://api.research.example/v1/search \
|
|
86
|
+
--method POST --params '{"query":"hi"}'
|
|
87
|
+
safety-guard pay --config guard_config.json \
|
|
88
|
+
--recipient 0xMerchant1111111111111111111111111111111 --usd 0.10
|
|
89
|
+
safety-guard serve --config guard_config.json # HTTP on 127.0.0.1:8080
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The HTTP surface (any agent, any language):
|
|
93
|
+
|
|
94
|
+
| Method | Path | Body |
|
|
95
|
+
| ------ | -------------- | ----------------------------------------------- |
|
|
96
|
+
| POST | `/guard` | `{action_type, target, method?, params?, cost?}` |
|
|
97
|
+
| POST | `/pay` | `{recipient, usd, resource?}` |
|
|
98
|
+
| POST | `/approve` | `{token, approved, approver}` |
|
|
99
|
+
| POST | `/killswitch` | `{reason}` |
|
|
100
|
+
| GET | `/audit` | — (immutable decision log) |
|
|
101
|
+
| GET | `/health` | — (status + lint summary) |
|
|
102
|
+
|
|
103
|
+
Equivalent module entry point: `python -m safety_protocol.guard_service --config guard_config.json`.
|
|
104
|
+
|
|
105
|
+
## Config reference
|
|
106
|
+
|
|
107
|
+
```jsonc
|
|
108
|
+
{
|
|
109
|
+
"agent_id": "guard-agent",
|
|
110
|
+
"user_id": "alice",
|
|
111
|
+
"budget_limit": 20.0, // global session cap (null = none)
|
|
112
|
+
"approval_threshold_cost": 2.0, // actions >= this need human sign-off
|
|
113
|
+
"allowed_action_types": ["api_call", "payment"], // closed verb vocabulary
|
|
114
|
+
"scope_rules": [
|
|
115
|
+
{
|
|
116
|
+
"action_type": "api_call",
|
|
117
|
+
"allowed_targets": ["https://api.research.example/v1/search"], // allowlist
|
|
118
|
+
"match": "exact", // exact | prefix | glob | regex
|
|
119
|
+
"methods": ["POST"], // transport verbs permitted
|
|
120
|
+
"param_schema": { // params MUST satisfy this
|
|
121
|
+
"required": ["query"],
|
|
122
|
+
"properties": {"query": {"type": "string", "maximum": 200}},
|
|
123
|
+
"additional_properties": false
|
|
124
|
+
},
|
|
125
|
+
"forbidden_targets": ["admin", "billing"],
|
|
126
|
+
"forbid_match": "token", // token | substring
|
|
127
|
+
"max_cost": 1.00, // per-rule cap (tightest wins)
|
|
128
|
+
"requires_approval": false
|
|
129
|
+
}
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Every dimension is enforced. Leaving any of them broad (a wildcard prefix, an
|
|
135
|
+
unbound method, an unvalidated param) is what makes the other controls
|
|
136
|
+
decorative — the `safety-guard lint` command exists to catch exactly that
|
|
137
|
+
before deploy.
|
|
138
|
+
|
|
139
|
+
## Architecture
|
|
140
|
+
|
|
141
|
+
| Layer | What it is | Status |
|
|
142
|
+
| ----- | ---------- | ------ |
|
|
143
|
+
| **1. Enforcement** | binding, scope, budget, approval, monitor, audit, killswitch | production-usable |
|
|
144
|
+
| **2. On-chain anchors** | SBT-style binding + on-chain audit of key events | **simulated** (in-memory, same interface as a real chain) |
|
|
145
|
+
| **3. Insurance** | claims evidence, underwriter reports | interface / reference |
|
|
146
|
+
|
|
147
|
+
> **The on-chain layer is simulated.** It is not third-party verifiable until a
|
|
148
|
+
> real contract is deployed. The library discloses this in every binding proof
|
|
149
|
+
> (`on_chain_backend: "simulated_in_memory"`). Use ERC-5192 SBT or ERC-8004 on a
|
|
150
|
+
> real chain in production.
|
|
151
|
+
|
|
152
|
+
`ReferenceDeployment` wires all three layers together; the layers are
|
|
153
|
+
composable and each adds value on its own.
|
|
154
|
+
|
|
155
|
+
## Development
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
pip install -e ".[dev]"
|
|
159
|
+
python -m pytest
|
|
160
|
+
ruff check
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
The repo-root files (`sovereign_agent.py`, `agent_capabilities.py`) are a
|
|
164
|
+
standalone demo agent and are **not** part of the package:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
pip install -e ".[demo]"
|
|
168
|
+
python sovereign_agent.py --offline # no API key needed; same gate logic
|
|
169
|
+
python sovereign_agent.py # live via NEBIUS_API_KEY
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Origin
|
|
173
|
+
|
|
174
|
+
Originally built for the Nebius x NVIDIA Global AI Hackathon (Track: Personal
|
|
175
|
+
AI), then hardened into a general enforcement library.
|
|
176
|
+
|
|
177
|
+
## License
|
|
178
|
+
|
|
179
|
+
MIT. See [`LICENSE`](LICENSE).
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
agent_client.py — a 'real' agent that calls the HTTP guard.
|
|
4
|
+
|
|
5
|
+
This is what an actual agent integration looks like: the agent forms an
|
|
6
|
+
intent, POSTs it to the guard, and only acts on an allow. It never sees
|
|
7
|
+
or edits the rules. Language-agnostic — any agent in any language hits
|
|
8
|
+
the same HTTP endpoints.
|
|
9
|
+
|
|
10
|
+
Prereq: python examples/cli.py serve --config examples/guard_config.json
|
|
11
|
+
Then: python examples/agent_client.py
|
|
12
|
+
"""
|
|
13
|
+
import sys, os, json, urllib.request
|
|
14
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))
|
|
15
|
+
|
|
16
|
+
BASE = "http://127.0.0.1:8080"
|
|
17
|
+
MERCHANT = "0xMerchant1111111111111111111111111111111111"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _post(path, payload):
|
|
21
|
+
req = urllib.request.Request(
|
|
22
|
+
BASE + path, data=json.dumps(payload).encode(),
|
|
23
|
+
headers={"Content-Type": "application/json"}, method="POST")
|
|
24
|
+
with urllib.request.urlopen(req, timeout=10) as r:
|
|
25
|
+
return json.loads(r.read().decode())
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def ask_guard(action_type, target, method=None, params=None, cost=0.0):
|
|
29
|
+
return _post("/guard", {
|
|
30
|
+
"action_type": action_type, "target": target,
|
|
31
|
+
"method": method, "params": params or {}, "cost": cost,
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def main():
|
|
36
|
+
# The agent's plan. It proposes; the guard disposes.
|
|
37
|
+
intents = [
|
|
38
|
+
("api_call", "https://api.research.example/v1/search",
|
|
39
|
+
"POST", {"query": "agent safety"}, 0.50),
|
|
40
|
+
("api_call", "https://api.research.example/v1/admin/config",
|
|
41
|
+
"POST", {"query": "x"}, 0.50), # forbidden token -> block
|
|
42
|
+
("payment", MERCHANT, "x402", {"resource": "weather"}, 0.10),
|
|
43
|
+
("payment", "0xEvil9999999999999999999999999999999999",
|
|
44
|
+
"x402", {"resource": "weather"}, 0.10), # forbidden recipient
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
print("AGENT running through the guard (guard decides, agent obeys)\n")
|
|
48
|
+
for action_type, target, method, params, cost in intents:
|
|
49
|
+
d = ask_guard(action_type, target, method, params, cost)
|
|
50
|
+
decision = "ALLOWED" if d["allowed"] else "BLOCKED"
|
|
51
|
+
print(f" intent: {action_type} {method or ''} {target}")
|
|
52
|
+
print(f" guard -> {decision}"
|
|
53
|
+
+ (f" ({d['block_reason']})" if d["block_reason"] else ""))
|
|
54
|
+
# The agent ONLY proceeds on allow. On block/approval it stops.
|
|
55
|
+
if d["allowed"]:
|
|
56
|
+
print(f" agent: proceeding with {action_type}")
|
|
57
|
+
else:
|
|
58
|
+
print(f" agent: NOT executing (guard denied)")
|
|
59
|
+
print()
|
|
60
|
+
|
|
61
|
+
# Show the audit trail the guard kept
|
|
62
|
+
print("GUARD AUDIT (every decision, immutable):")
|
|
63
|
+
with urllib.request.urlopen(BASE + "/audit", timeout=10) as r:
|
|
64
|
+
events = json.loads(r.read().decode()).get("events", [])
|
|
65
|
+
for e in events[-6:]:
|
|
66
|
+
print(f" [{e['event_type']}] {e.get('data', {}).get('target', '')}")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
if __name__ == "__main__":
|
|
70
|
+
main()
|