waveframe-guard 0.1.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.
- waveframe_guard-0.1.0/LICENSE +7 -0
- waveframe_guard-0.1.0/PKG-INFO +190 -0
- waveframe_guard-0.1.0/README.md +178 -0
- waveframe_guard-0.1.0/examples/finance_usage.py +121 -0
- waveframe_guard-0.1.0/pyproject.toml +23 -0
- waveframe_guard-0.1.0/setup.cfg +4 -0
- waveframe_guard-0.1.0/waveframe_guard/__init__.py +13 -0
- waveframe_guard-0.1.0/waveframe_guard/client.py +279 -0
- waveframe_guard-0.1.0/waveframe_guard.egg-info/PKG-INFO +190 -0
- waveframe_guard-0.1.0/waveframe_guard.egg-info/SOURCES.txt +11 -0
- waveframe_guard-0.1.0/waveframe_guard.egg-info/dependency_links.txt +1 -0
- waveframe_guard-0.1.0/waveframe_guard.egg-info/requires.txt +1 -0
- waveframe_guard-0.1.0/waveframe_guard.egg-info/top_level.txt +4 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: waveframe-guard
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Stop unsafe AI actions before they execute
|
|
5
|
+
Author-email: Shawn Wright <swright@waveframelabs.org>
|
|
6
|
+
License: Proprietary
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: cricore
|
|
11
|
+
Dynamic: license-file
|
|
12
|
+
|
|
13
|
+
# Waveframe Guard
|
|
14
|
+
|
|
15
|
+
Deterministic execution control for AI agents.
|
|
16
|
+
|
|
17
|
+
Stop unauthorized AI actions—from rogue financial transfers to unapproved budget reallocations—in a single function call.
|
|
18
|
+
|
|
19
|
+
Prevent costly mistakes before they hit production systems.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## The execution boundary
|
|
24
|
+
|
|
25
|
+
Most AI governance tools act as monitors: they log, flag, and alert after a mistake has already happened.
|
|
26
|
+
|
|
27
|
+
Waveframe Guard sits directly at the execution boundary. It evaluates every proposed action before it ever reaches your backend or mutates state.
|
|
28
|
+
|
|
29
|
+
The evaluation is deterministic and the result is binary:
|
|
30
|
+
|
|
31
|
+
- **Allowed** → execution proceeds seamlessly
|
|
32
|
+
- **Blocked** → execution is stopped before it reaches your system
|
|
33
|
+
|
|
34
|
+
No warnings. No post-hoc analysis. The action either happens, or it doesn’t.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## A drop-in execution gate
|
|
39
|
+
|
|
40
|
+
Integrate Waveframe Guard into your workflow in minutes.
|
|
41
|
+
|
|
42
|
+
Initialize the SDK with your compiled governance policy, pass the proposed AI action, and let Guard handle the evaluation.
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from waveframe_guard import WaveframeGuard
|
|
46
|
+
|
|
47
|
+
guard = WaveframeGuard(policy="finance-policy.json")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def execute_transfer(action):
|
|
51
|
+
return {
|
|
52
|
+
"status": "executed",
|
|
53
|
+
"details": action
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def process_ai_action(action, actor, context=None):
|
|
58
|
+
decision = guard.execute(
|
|
59
|
+
action=action,
|
|
60
|
+
actor=actor,
|
|
61
|
+
context=context
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
if decision["allowed"]:
|
|
65
|
+
return execute_transfer(action)
|
|
66
|
+
else:
|
|
67
|
+
return {
|
|
68
|
+
"status": "blocked",
|
|
69
|
+
"reason": decision["reason"]
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
result = process_ai_action(
|
|
74
|
+
action={"type": "transfer", "amount": 5000},
|
|
75
|
+
actor="ai-agent",
|
|
76
|
+
context={"approved_by": "human-123"}
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
print(result)
|
|
80
|
+
````
|
|
81
|
+
|
|
82
|
+
Waveframe Guard does not execute actions.
|
|
83
|
+
|
|
84
|
+
It decides whether execution is allowed.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Predictable, standardized outputs
|
|
89
|
+
|
|
90
|
+
Guard returns a strict, predictable response so your application can route logic deterministically.
|
|
91
|
+
|
|
92
|
+
**Authorized attempt:**
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"allowed": true,
|
|
97
|
+
"reason": "Allowed: execution permitted"
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
**Unauthorized attempt (missing approval):**
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"allowed": false,
|
|
108
|
+
"reason": "Blocked: approval required (no approver provided)"
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Built for financial-grade governance
|
|
115
|
+
|
|
116
|
+
Waveframe Guard is designed for high-stakes autonomous systems.
|
|
117
|
+
|
|
118
|
+
* **Separation of duties**
|
|
119
|
+
The actor proposing an action cannot approve it.
|
|
120
|
+
|
|
121
|
+
* **Approval requirements**
|
|
122
|
+
Human authorization is required for sensitive actions.
|
|
123
|
+
|
|
124
|
+
* **Action-level constraints**
|
|
125
|
+
Define exactly what an agent is allowed to do.
|
|
126
|
+
|
|
127
|
+
* **No state stored**
|
|
128
|
+
Your system remains in full control.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Clear boundaries
|
|
133
|
+
|
|
134
|
+
Waveframe Guard focuses on one responsibility:
|
|
135
|
+
|
|
136
|
+
👉 deciding whether an action can execute
|
|
137
|
+
|
|
138
|
+
It does not:
|
|
139
|
+
|
|
140
|
+
* run workflows
|
|
141
|
+
* manage approvals
|
|
142
|
+
* store policies
|
|
143
|
+
* maintain system state
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Getting started
|
|
148
|
+
|
|
149
|
+
Waveframe Guard is in active development, focused on financial governance and autonomous agent control.
|
|
150
|
+
|
|
151
|
+
### Local installation
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
pip install -e .
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
*(PyPI release coming soon)*
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
### Run the example
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
python examples/finance_usage.py
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Policy
|
|
170
|
+
|
|
171
|
+
Policies represent compiled governance rules.
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
guard = WaveframeGuard(policy="finance-policy.json")
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
These rules define:
|
|
178
|
+
|
|
179
|
+
* who can approve actions
|
|
180
|
+
* what actions require approval
|
|
181
|
+
* role separation requirements
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
<div align="center">
|
|
186
|
+
<sub><b>Proprietary / Commercial License (Pending)</b></sub>
|
|
187
|
+
<br>
|
|
188
|
+
<sub>© 2026 Waveframe Labs</sub>
|
|
189
|
+
</div>
|
|
190
|
+
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# Waveframe Guard
|
|
2
|
+
|
|
3
|
+
Deterministic execution control for AI agents.
|
|
4
|
+
|
|
5
|
+
Stop unauthorized AI actions—from rogue financial transfers to unapproved budget reallocations—in a single function call.
|
|
6
|
+
|
|
7
|
+
Prevent costly mistakes before they hit production systems.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## The execution boundary
|
|
12
|
+
|
|
13
|
+
Most AI governance tools act as monitors: they log, flag, and alert after a mistake has already happened.
|
|
14
|
+
|
|
15
|
+
Waveframe Guard sits directly at the execution boundary. It evaluates every proposed action before it ever reaches your backend or mutates state.
|
|
16
|
+
|
|
17
|
+
The evaluation is deterministic and the result is binary:
|
|
18
|
+
|
|
19
|
+
- **Allowed** → execution proceeds seamlessly
|
|
20
|
+
- **Blocked** → execution is stopped before it reaches your system
|
|
21
|
+
|
|
22
|
+
No warnings. No post-hoc analysis. The action either happens, or it doesn’t.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## A drop-in execution gate
|
|
27
|
+
|
|
28
|
+
Integrate Waveframe Guard into your workflow in minutes.
|
|
29
|
+
|
|
30
|
+
Initialize the SDK with your compiled governance policy, pass the proposed AI action, and let Guard handle the evaluation.
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from waveframe_guard import WaveframeGuard
|
|
34
|
+
|
|
35
|
+
guard = WaveframeGuard(policy="finance-policy.json")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def execute_transfer(action):
|
|
39
|
+
return {
|
|
40
|
+
"status": "executed",
|
|
41
|
+
"details": action
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def process_ai_action(action, actor, context=None):
|
|
46
|
+
decision = guard.execute(
|
|
47
|
+
action=action,
|
|
48
|
+
actor=actor,
|
|
49
|
+
context=context
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
if decision["allowed"]:
|
|
53
|
+
return execute_transfer(action)
|
|
54
|
+
else:
|
|
55
|
+
return {
|
|
56
|
+
"status": "blocked",
|
|
57
|
+
"reason": decision["reason"]
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
result = process_ai_action(
|
|
62
|
+
action={"type": "transfer", "amount": 5000},
|
|
63
|
+
actor="ai-agent",
|
|
64
|
+
context={"approved_by": "human-123"}
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
print(result)
|
|
68
|
+
````
|
|
69
|
+
|
|
70
|
+
Waveframe Guard does not execute actions.
|
|
71
|
+
|
|
72
|
+
It decides whether execution is allowed.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Predictable, standardized outputs
|
|
77
|
+
|
|
78
|
+
Guard returns a strict, predictable response so your application can route logic deterministically.
|
|
79
|
+
|
|
80
|
+
**Authorized attempt:**
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"allowed": true,
|
|
85
|
+
"reason": "Allowed: execution permitted"
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
**Unauthorized attempt (missing approval):**
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"allowed": false,
|
|
96
|
+
"reason": "Blocked: approval required (no approver provided)"
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Built for financial-grade governance
|
|
103
|
+
|
|
104
|
+
Waveframe Guard is designed for high-stakes autonomous systems.
|
|
105
|
+
|
|
106
|
+
* **Separation of duties**
|
|
107
|
+
The actor proposing an action cannot approve it.
|
|
108
|
+
|
|
109
|
+
* **Approval requirements**
|
|
110
|
+
Human authorization is required for sensitive actions.
|
|
111
|
+
|
|
112
|
+
* **Action-level constraints**
|
|
113
|
+
Define exactly what an agent is allowed to do.
|
|
114
|
+
|
|
115
|
+
* **No state stored**
|
|
116
|
+
Your system remains in full control.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Clear boundaries
|
|
121
|
+
|
|
122
|
+
Waveframe Guard focuses on one responsibility:
|
|
123
|
+
|
|
124
|
+
👉 deciding whether an action can execute
|
|
125
|
+
|
|
126
|
+
It does not:
|
|
127
|
+
|
|
128
|
+
* run workflows
|
|
129
|
+
* manage approvals
|
|
130
|
+
* store policies
|
|
131
|
+
* maintain system state
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Getting started
|
|
136
|
+
|
|
137
|
+
Waveframe Guard is in active development, focused on financial governance and autonomous agent control.
|
|
138
|
+
|
|
139
|
+
### Local installation
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
pip install -e .
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
*(PyPI release coming soon)*
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
### Run the example
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
python examples/finance_usage.py
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Policy
|
|
158
|
+
|
|
159
|
+
Policies represent compiled governance rules.
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
guard = WaveframeGuard(policy="finance-policy.json")
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
These rules define:
|
|
166
|
+
|
|
167
|
+
* who can approve actions
|
|
168
|
+
* what actions require approval
|
|
169
|
+
* role separation requirements
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
<div align="center">
|
|
174
|
+
<sub><b>Proprietary / Commercial License (Pending)</b></sub>
|
|
175
|
+
<br>
|
|
176
|
+
<sub>© 2026 Waveframe Labs</sub>
|
|
177
|
+
</div>
|
|
178
|
+
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Waveframe Guard — Production Usage Example
|
|
3
|
+
|
|
4
|
+
This shows how a backend service would use Waveframe Guard
|
|
5
|
+
to evaluate AI-generated financial actions BEFORE execution.
|
|
6
|
+
|
|
7
|
+
Run:
|
|
8
|
+
python examples/finance_usage.py
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from waveframe_guard import WaveframeGuard
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# --------------------------------------------------
|
|
15
|
+
# Load compiled governance policy
|
|
16
|
+
# --------------------------------------------------
|
|
17
|
+
|
|
18
|
+
# In production, this would come from a file or config system
|
|
19
|
+
policy = "finance-policy.json"
|
|
20
|
+
|
|
21
|
+
guard = WaveframeGuard(policy=policy)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# --------------------------------------------------
|
|
25
|
+
# Simulated execution layer (your actual system)
|
|
26
|
+
# --------------------------------------------------
|
|
27
|
+
|
|
28
|
+
def execute_transfer(action: dict):
|
|
29
|
+
"""
|
|
30
|
+
This represents your real system performing the action.
|
|
31
|
+
Only called if guard allows execution.
|
|
32
|
+
"""
|
|
33
|
+
return {
|
|
34
|
+
"status": "executed",
|
|
35
|
+
"details": action
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# --------------------------------------------------
|
|
40
|
+
# Core evaluation wrapper
|
|
41
|
+
# --------------------------------------------------
|
|
42
|
+
|
|
43
|
+
def process_action(action: dict, actor: str, context: dict | None = None):
|
|
44
|
+
"""
|
|
45
|
+
Standard pattern:
|
|
46
|
+
|
|
47
|
+
1. Evaluate with Waveframe Guard
|
|
48
|
+
2. If allowed → execute
|
|
49
|
+
3. If blocked → stop
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
decision = guard.execute(
|
|
53
|
+
action=action,
|
|
54
|
+
actor=actor,
|
|
55
|
+
context=context
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
if not decision["allowed"]:
|
|
59
|
+
return {
|
|
60
|
+
"status": "blocked",
|
|
61
|
+
"reason": decision["reason"]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
result = execute_transfer(action)
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
"status": "executed",
|
|
68
|
+
"result": result
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# --------------------------------------------------
|
|
73
|
+
# Example scenarios (real-world style)
|
|
74
|
+
# --------------------------------------------------
|
|
75
|
+
|
|
76
|
+
def main():
|
|
77
|
+
|
|
78
|
+
print("\n--- Scenario 1: Missing approval ---")
|
|
79
|
+
|
|
80
|
+
result_1 = process_action(
|
|
81
|
+
action={"type": "transfer", "amount": 5000},
|
|
82
|
+
actor="ai-agent"
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
print(result_1)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
print("\n--- Scenario 2: Invalid approval (same actor) ---")
|
|
89
|
+
|
|
90
|
+
result_2 = process_action(
|
|
91
|
+
action={"type": "transfer", "amount": 5000},
|
|
92
|
+
actor="ai-agent",
|
|
93
|
+
context={"approved_by": "ai-agent"}
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
print(result_2)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
print("\n--- Scenario 3: Valid approval ---")
|
|
100
|
+
|
|
101
|
+
result_3 = process_action(
|
|
102
|
+
action={"type": "transfer", "amount": 5000},
|
|
103
|
+
actor="ai-agent",
|
|
104
|
+
context={"approved_by": "human-123"}
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
print(result_3)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
print("\n--- Scenario 4: Read-only action ---")
|
|
111
|
+
|
|
112
|
+
result_4 = process_action(
|
|
113
|
+
action={"type": "get_balance"},
|
|
114
|
+
actor="ai-agent"
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
print(result_4)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
if __name__ == "__main__":
|
|
121
|
+
main()
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "waveframe-guard"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Stop unsafe AI actions before they execute"
|
|
9
|
+
authors = [
|
|
10
|
+
{ name = "Shawn Wright", email = "swright@waveframelabs.org" }
|
|
11
|
+
]
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.10"
|
|
14
|
+
|
|
15
|
+
# 🔒 Proprietary license
|
|
16
|
+
license = { text = "Proprietary" }
|
|
17
|
+
|
|
18
|
+
dependencies = [
|
|
19
|
+
"cricore"
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
[tool.setuptools.packages.find]
|
|
23
|
+
where = ["."]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Waveframe Guard — Public API
|
|
3
|
+
|
|
4
|
+
This module exposes the primary SDK interface.
|
|
5
|
+
|
|
6
|
+
Users should only need to import from here:
|
|
7
|
+
|
|
8
|
+
from waveframe_guard import WaveframeGuard
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from .client import WaveframeGuard
|
|
12
|
+
|
|
13
|
+
__all__ = ["WaveframeGuard"]
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any, Dict, Optional
|
|
5
|
+
import json
|
|
6
|
+
import tempfile
|
|
7
|
+
import uuid
|
|
8
|
+
|
|
9
|
+
from compiler.compile_policy_file import compile_policy_file
|
|
10
|
+
from proposal_normalizer import build_proposal
|
|
11
|
+
from cricore.interface.evaluate_proposal import evaluate_proposal
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class WaveframeGuard:
|
|
15
|
+
"""
|
|
16
|
+
Waveframe Guard
|
|
17
|
+
|
|
18
|
+
Product-facing SDK that evaluates whether an AI-generated action
|
|
19
|
+
is allowed to execute using CRI-CORE enforcement.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self, policy: Any):
|
|
23
|
+
self.policy_path = self._resolve_policy_path(policy)
|
|
24
|
+
self.raw_policy = self._load_policy_json(self.policy_path)
|
|
25
|
+
self.compiled_contract = self._compile_policy(self.policy_path)
|
|
26
|
+
|
|
27
|
+
# --------------------------------------------------
|
|
28
|
+
# Public API
|
|
29
|
+
# --------------------------------------------------
|
|
30
|
+
|
|
31
|
+
def execute(
|
|
32
|
+
self,
|
|
33
|
+
action: Dict[str, Any],
|
|
34
|
+
actor: str,
|
|
35
|
+
context: Optional[Dict[str, Any]] = None,
|
|
36
|
+
) -> Dict[str, Any]:
|
|
37
|
+
|
|
38
|
+
# -----------------------------
|
|
39
|
+
# Input validation
|
|
40
|
+
# -----------------------------
|
|
41
|
+
|
|
42
|
+
if not isinstance(action, dict):
|
|
43
|
+
return {
|
|
44
|
+
"allowed": False,
|
|
45
|
+
"reason": "Invalid request: action must be a dictionary",
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if "type" not in action:
|
|
49
|
+
return {
|
|
50
|
+
"allowed": False,
|
|
51
|
+
"reason": "Invalid request: action must include a 'type' field",
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if context is not None and not isinstance(context, dict):
|
|
55
|
+
return {
|
|
56
|
+
"allowed": False,
|
|
57
|
+
"reason": "Invalid request: context must be a dictionary",
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
context = context or {}
|
|
61
|
+
action_type = action["type"]
|
|
62
|
+
approved_by = context.get("approved_by")
|
|
63
|
+
|
|
64
|
+
# -----------------------------
|
|
65
|
+
# Read policy rules
|
|
66
|
+
# -----------------------------
|
|
67
|
+
|
|
68
|
+
rules = self.raw_policy.get("rules", {})
|
|
69
|
+
action_rules = rules.get(action_type, {})
|
|
70
|
+
|
|
71
|
+
requires_approval = action_rules.get("requires_approval", False)
|
|
72
|
+
read_only = action_rules.get("read_only", False)
|
|
73
|
+
|
|
74
|
+
# -----------------------------
|
|
75
|
+
# Read-only shortcut
|
|
76
|
+
# -----------------------------
|
|
77
|
+
|
|
78
|
+
if read_only:
|
|
79
|
+
return {
|
|
80
|
+
"allowed": True,
|
|
81
|
+
"reason": "Allowed: read-only action",
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
# -----------------------------
|
|
85
|
+
# Approval enforcement
|
|
86
|
+
# -----------------------------
|
|
87
|
+
|
|
88
|
+
if requires_approval:
|
|
89
|
+
|
|
90
|
+
if not approved_by:
|
|
91
|
+
return {
|
|
92
|
+
"allowed": False,
|
|
93
|
+
"reason": "Blocked: approval required (no approver provided)",
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if approved_by == actor:
|
|
97
|
+
return {
|
|
98
|
+
"allowed": False,
|
|
99
|
+
"reason": "Blocked: separation of duties violated (proposer cannot approve)",
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
# -----------------------------
|
|
103
|
+
# Normalize action → mutation
|
|
104
|
+
# -----------------------------
|
|
105
|
+
|
|
106
|
+
mutation = self._normalize_action(action)
|
|
107
|
+
|
|
108
|
+
# -----------------------------
|
|
109
|
+
# Build run_context
|
|
110
|
+
# -----------------------------
|
|
111
|
+
|
|
112
|
+
run_context = self._build_run_context(
|
|
113
|
+
actor=actor,
|
|
114
|
+
approved_by=approved_by,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# -----------------------------
|
|
118
|
+
# Build proposal
|
|
119
|
+
# -----------------------------
|
|
120
|
+
|
|
121
|
+
try:
|
|
122
|
+
proposal = build_proposal(
|
|
123
|
+
proposal_id=str(uuid.uuid4()),
|
|
124
|
+
actor={"id": actor, "type": "agent"},
|
|
125
|
+
artifact_paths=[],
|
|
126
|
+
mutation=mutation,
|
|
127
|
+
contract=self._proposal_contract_binding(self.compiled_contract),
|
|
128
|
+
run_context=run_context,
|
|
129
|
+
)
|
|
130
|
+
except Exception:
|
|
131
|
+
return {
|
|
132
|
+
"allowed": False,
|
|
133
|
+
"reason": "Blocked: proposal construction failed",
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
# -----------------------------
|
|
137
|
+
# Evaluate with CRI-CORE
|
|
138
|
+
# -----------------------------
|
|
139
|
+
|
|
140
|
+
try:
|
|
141
|
+
result = evaluate_proposal(proposal, self.compiled_contract)
|
|
142
|
+
except Exception:
|
|
143
|
+
return {
|
|
144
|
+
"allowed": False,
|
|
145
|
+
"reason": "Blocked: enforcement execution failed",
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
# -----------------------------
|
|
149
|
+
# Translate result
|
|
150
|
+
# -----------------------------
|
|
151
|
+
|
|
152
|
+
if getattr(result, "commit_allowed", False):
|
|
153
|
+
return {
|
|
154
|
+
"allowed": True,
|
|
155
|
+
"reason": "Allowed: execution permitted",
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return {
|
|
159
|
+
"allowed": False,
|
|
160
|
+
"reason": self._extract_reason(result),
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
# --------------------------------------------------
|
|
164
|
+
# Internal helpers
|
|
165
|
+
# --------------------------------------------------
|
|
166
|
+
|
|
167
|
+
def _resolve_policy_path(self, policy: Any) -> Path:
|
|
168
|
+
if isinstance(policy, str):
|
|
169
|
+
path = Path(policy)
|
|
170
|
+
if not path.exists():
|
|
171
|
+
raise FileNotFoundError(f"Policy file not found: {policy}")
|
|
172
|
+
return path
|
|
173
|
+
|
|
174
|
+
if isinstance(policy, dict):
|
|
175
|
+
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".json")
|
|
176
|
+
temp_path = Path(temp_file.name)
|
|
177
|
+
temp_file.close()
|
|
178
|
+
temp_path.write_text(json.dumps(policy), encoding="utf-8")
|
|
179
|
+
return temp_path
|
|
180
|
+
|
|
181
|
+
raise ValueError("Policy must be a file path or dictionary")
|
|
182
|
+
|
|
183
|
+
def _load_policy_json(self, policy_path: Path) -> Dict[str, Any]:
|
|
184
|
+
with policy_path.open("r", encoding="utf-8") as f:
|
|
185
|
+
return json.load(f)
|
|
186
|
+
|
|
187
|
+
def _compile_policy(self, policy_path: Path) -> Dict[str, Any]:
|
|
188
|
+
temp_output = tempfile.NamedTemporaryFile(delete=False, suffix=".json")
|
|
189
|
+
output_path = Path(temp_output.name)
|
|
190
|
+
temp_output.close()
|
|
191
|
+
|
|
192
|
+
compiled_path = compile_policy_file(policy_path, output_path)
|
|
193
|
+
|
|
194
|
+
with Path(compiled_path).open("r", encoding="utf-8") as f:
|
|
195
|
+
return json.load(f)
|
|
196
|
+
|
|
197
|
+
def _proposal_contract_binding(self, compiled_contract: Dict[str, Any]) -> Dict[str, Any]:
|
|
198
|
+
return {
|
|
199
|
+
"id": compiled_contract["contract_id"],
|
|
200
|
+
"version": compiled_contract["contract_version"],
|
|
201
|
+
"hash": compiled_contract["contract_hash"],
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
def _normalize_action(self, action: Dict[str, Any]) -> Dict[str, Any]:
|
|
205
|
+
action_type = action["type"]
|
|
206
|
+
|
|
207
|
+
if action_type == "transfer":
|
|
208
|
+
return {
|
|
209
|
+
"domain": "finance",
|
|
210
|
+
"resource": "funds",
|
|
211
|
+
"action": "transfer",
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if action_type == "get_balance":
|
|
215
|
+
return {
|
|
216
|
+
"domain": "finance",
|
|
217
|
+
"resource": "account",
|
|
218
|
+
"action": "read",
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
"domain": "general",
|
|
223
|
+
"resource": "unknown",
|
|
224
|
+
"action": action_type,
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
def _build_run_context(
|
|
228
|
+
self,
|
|
229
|
+
actor: str,
|
|
230
|
+
approved_by: Optional[str],
|
|
231
|
+
) -> Dict[str, Any]:
|
|
232
|
+
|
|
233
|
+
actors = [
|
|
234
|
+
{
|
|
235
|
+
"id": actor,
|
|
236
|
+
"type": "agent",
|
|
237
|
+
"role": "proposer",
|
|
238
|
+
}
|
|
239
|
+
]
|
|
240
|
+
|
|
241
|
+
if approved_by:
|
|
242
|
+
actors.append(
|
|
243
|
+
{
|
|
244
|
+
"id": approved_by,
|
|
245
|
+
"type": "human",
|
|
246
|
+
"role": "approver",
|
|
247
|
+
}
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
return {
|
|
251
|
+
"identities": {
|
|
252
|
+
"actors": actors,
|
|
253
|
+
"required_roles": ["proposer", "approver"],
|
|
254
|
+
"conflict_flags": {},
|
|
255
|
+
},
|
|
256
|
+
"integrity": {},
|
|
257
|
+
"publication": {},
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
def _extract_reason(self, result: Any) -> str:
|
|
261
|
+
failed_stages = getattr(result, "failed_stages", None)
|
|
262
|
+
summary = getattr(result, "summary", None)
|
|
263
|
+
|
|
264
|
+
if not failed_stages:
|
|
265
|
+
return summary or "Blocked: policy violation"
|
|
266
|
+
|
|
267
|
+
if "independence" in failed_stages:
|
|
268
|
+
return "Blocked: separation of duties violated (proposer cannot approve)"
|
|
269
|
+
|
|
270
|
+
if "publication-commit" in failed_stages:
|
|
271
|
+
return "Blocked: approval required (no approver provided)"
|
|
272
|
+
|
|
273
|
+
if "integrity" in failed_stages:
|
|
274
|
+
return "Blocked: required execution data missing"
|
|
275
|
+
|
|
276
|
+
if "publication" in failed_stages:
|
|
277
|
+
return "Blocked: execution context incomplete"
|
|
278
|
+
|
|
279
|
+
return summary or "Blocked: policy violation"
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: waveframe-guard
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Stop unsafe AI actions before they execute
|
|
5
|
+
Author-email: Shawn Wright <swright@waveframelabs.org>
|
|
6
|
+
License: Proprietary
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: cricore
|
|
11
|
+
Dynamic: license-file
|
|
12
|
+
|
|
13
|
+
# Waveframe Guard
|
|
14
|
+
|
|
15
|
+
Deterministic execution control for AI agents.
|
|
16
|
+
|
|
17
|
+
Stop unauthorized AI actions—from rogue financial transfers to unapproved budget reallocations—in a single function call.
|
|
18
|
+
|
|
19
|
+
Prevent costly mistakes before they hit production systems.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## The execution boundary
|
|
24
|
+
|
|
25
|
+
Most AI governance tools act as monitors: they log, flag, and alert after a mistake has already happened.
|
|
26
|
+
|
|
27
|
+
Waveframe Guard sits directly at the execution boundary. It evaluates every proposed action before it ever reaches your backend or mutates state.
|
|
28
|
+
|
|
29
|
+
The evaluation is deterministic and the result is binary:
|
|
30
|
+
|
|
31
|
+
- **Allowed** → execution proceeds seamlessly
|
|
32
|
+
- **Blocked** → execution is stopped before it reaches your system
|
|
33
|
+
|
|
34
|
+
No warnings. No post-hoc analysis. The action either happens, or it doesn’t.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## A drop-in execution gate
|
|
39
|
+
|
|
40
|
+
Integrate Waveframe Guard into your workflow in minutes.
|
|
41
|
+
|
|
42
|
+
Initialize the SDK with your compiled governance policy, pass the proposed AI action, and let Guard handle the evaluation.
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from waveframe_guard import WaveframeGuard
|
|
46
|
+
|
|
47
|
+
guard = WaveframeGuard(policy="finance-policy.json")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def execute_transfer(action):
|
|
51
|
+
return {
|
|
52
|
+
"status": "executed",
|
|
53
|
+
"details": action
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def process_ai_action(action, actor, context=None):
|
|
58
|
+
decision = guard.execute(
|
|
59
|
+
action=action,
|
|
60
|
+
actor=actor,
|
|
61
|
+
context=context
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
if decision["allowed"]:
|
|
65
|
+
return execute_transfer(action)
|
|
66
|
+
else:
|
|
67
|
+
return {
|
|
68
|
+
"status": "blocked",
|
|
69
|
+
"reason": decision["reason"]
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
result = process_ai_action(
|
|
74
|
+
action={"type": "transfer", "amount": 5000},
|
|
75
|
+
actor="ai-agent",
|
|
76
|
+
context={"approved_by": "human-123"}
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
print(result)
|
|
80
|
+
````
|
|
81
|
+
|
|
82
|
+
Waveframe Guard does not execute actions.
|
|
83
|
+
|
|
84
|
+
It decides whether execution is allowed.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Predictable, standardized outputs
|
|
89
|
+
|
|
90
|
+
Guard returns a strict, predictable response so your application can route logic deterministically.
|
|
91
|
+
|
|
92
|
+
**Authorized attempt:**
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"allowed": true,
|
|
97
|
+
"reason": "Allowed: execution permitted"
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
**Unauthorized attempt (missing approval):**
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"allowed": false,
|
|
108
|
+
"reason": "Blocked: approval required (no approver provided)"
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Built for financial-grade governance
|
|
115
|
+
|
|
116
|
+
Waveframe Guard is designed for high-stakes autonomous systems.
|
|
117
|
+
|
|
118
|
+
* **Separation of duties**
|
|
119
|
+
The actor proposing an action cannot approve it.
|
|
120
|
+
|
|
121
|
+
* **Approval requirements**
|
|
122
|
+
Human authorization is required for sensitive actions.
|
|
123
|
+
|
|
124
|
+
* **Action-level constraints**
|
|
125
|
+
Define exactly what an agent is allowed to do.
|
|
126
|
+
|
|
127
|
+
* **No state stored**
|
|
128
|
+
Your system remains in full control.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Clear boundaries
|
|
133
|
+
|
|
134
|
+
Waveframe Guard focuses on one responsibility:
|
|
135
|
+
|
|
136
|
+
👉 deciding whether an action can execute
|
|
137
|
+
|
|
138
|
+
It does not:
|
|
139
|
+
|
|
140
|
+
* run workflows
|
|
141
|
+
* manage approvals
|
|
142
|
+
* store policies
|
|
143
|
+
* maintain system state
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Getting started
|
|
148
|
+
|
|
149
|
+
Waveframe Guard is in active development, focused on financial governance and autonomous agent control.
|
|
150
|
+
|
|
151
|
+
### Local installation
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
pip install -e .
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
*(PyPI release coming soon)*
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
### Run the example
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
python examples/finance_usage.py
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Policy
|
|
170
|
+
|
|
171
|
+
Policies represent compiled governance rules.
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
guard = WaveframeGuard(policy="finance-policy.json")
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
These rules define:
|
|
178
|
+
|
|
179
|
+
* who can approve actions
|
|
180
|
+
* what actions require approval
|
|
181
|
+
* role separation requirements
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
<div align="center">
|
|
186
|
+
<sub><b>Proprietary / Commercial License (Pending)</b></sub>
|
|
187
|
+
<br>
|
|
188
|
+
<sub>© 2026 Waveframe Labs</sub>
|
|
189
|
+
</div>
|
|
190
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
examples/finance_usage.py
|
|
5
|
+
waveframe_guard/__init__.py
|
|
6
|
+
waveframe_guard/client.py
|
|
7
|
+
waveframe_guard.egg-info/PKG-INFO
|
|
8
|
+
waveframe_guard.egg-info/SOURCES.txt
|
|
9
|
+
waveframe_guard.egg-info/dependency_links.txt
|
|
10
|
+
waveframe_guard.egg-info/requires.txt
|
|
11
|
+
waveframe_guard.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cricore
|