openclaw-safeclaw-plugin 0.8.2 → 0.9.0
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.
- package/dist/index.js +32 -3
- package/index.ts +38 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -53,6 +53,24 @@ async function post(path, body) {
|
|
|
53
53
|
return null; // Caller checks failMode
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
|
+
let handshakeCompleted = false;
|
|
57
|
+
async function performHandshake() {
|
|
58
|
+
if (!config.apiKey) {
|
|
59
|
+
console.warn('[SafeClaw] No API key configured — skipping handshake');
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
const r = await post('/handshake', {
|
|
63
|
+
pluginVersion: '0.1.3',
|
|
64
|
+
configHash: configHash(config),
|
|
65
|
+
});
|
|
66
|
+
if (r === null) {
|
|
67
|
+
console.warn('[SafeClaw] ✗ Handshake failed — API key may be invalid or service unreachable');
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
console.log(`[SafeClaw] ✓ Handshake OK — org=${r.orgId}, scope=${r.scope}, engine=${r.engineReady ? 'ready' : 'not ready'}`);
|
|
71
|
+
handshakeCompleted = true;
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
56
74
|
async function checkConnection() {
|
|
57
75
|
const label = `[SafeClaw]`;
|
|
58
76
|
console.log(`${label} Connecting to ${config.serviceUrl} ...`);
|
|
@@ -82,7 +100,7 @@ async function checkConnection() {
|
|
|
82
100
|
export default {
|
|
83
101
|
id: 'safeclaw',
|
|
84
102
|
name: 'SafeClaw Neurosymbolic Governance',
|
|
85
|
-
version: '0.1.
|
|
103
|
+
version: '0.1.3',
|
|
86
104
|
register(api) {
|
|
87
105
|
if (!config.enabled) {
|
|
88
106
|
console.log('[SafeClaw] Plugin disabled');
|
|
@@ -106,8 +124,16 @@ export default {
|
|
|
106
124
|
// Heartbeat failure is non-fatal
|
|
107
125
|
}
|
|
108
126
|
};
|
|
109
|
-
// Start heartbeat after connection check
|
|
110
|
-
checkConnection()
|
|
127
|
+
// Start heartbeat after connection check + handshake
|
|
128
|
+
checkConnection()
|
|
129
|
+
.then(() => performHandshake())
|
|
130
|
+
.then((ok) => {
|
|
131
|
+
if (!ok && config.failMode === 'closed') {
|
|
132
|
+
console.warn('[SafeClaw] ⚠ Handshake failed with fail-mode=closed — tool calls will be BLOCKED');
|
|
133
|
+
}
|
|
134
|
+
return sendHeartbeat();
|
|
135
|
+
})
|
|
136
|
+
.catch(() => { });
|
|
111
137
|
const heartbeatInterval = setInterval(sendHeartbeat, 30000);
|
|
112
138
|
// Clean shutdown: send shutdown heartbeat and clear interval
|
|
113
139
|
const shutdown = () => {
|
|
@@ -127,6 +153,9 @@ export default {
|
|
|
127
153
|
process.on('SIGTERM', () => { shutdown(); process.exit(0); });
|
|
128
154
|
// THE GATE — constraint checking on every tool call
|
|
129
155
|
api.on('before_tool_call', async (event, ctx) => {
|
|
156
|
+
if (!handshakeCompleted && config.failMode === 'closed' && config.enforcement === 'enforce') {
|
|
157
|
+
return { block: true, blockReason: 'SafeClaw handshake not completed (fail-closed)' };
|
|
158
|
+
}
|
|
130
159
|
const r = await post('/evaluate/tool-call', {
|
|
131
160
|
sessionId: ctx.sessionId ?? event.sessionId,
|
|
132
161
|
userId: ctx.userId ?? event.userId,
|
package/index.ts
CHANGED
|
@@ -79,6 +79,29 @@ interface PluginApi {
|
|
|
79
79
|
): void;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
let handshakeCompleted = false;
|
|
83
|
+
|
|
84
|
+
async function performHandshake(): Promise<boolean> {
|
|
85
|
+
if (!config.apiKey) {
|
|
86
|
+
console.warn('[SafeClaw] No API key configured — skipping handshake');
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const r = await post('/handshake', {
|
|
91
|
+
pluginVersion: '0.1.3',
|
|
92
|
+
configHash: configHash(config),
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
if (r === null) {
|
|
96
|
+
console.warn('[SafeClaw] ✗ Handshake failed — API key may be invalid or service unreachable');
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
console.log(`[SafeClaw] ✓ Handshake OK — org=${r.orgId}, scope=${r.scope}, engine=${r.engineReady ? 'ready' : 'not ready'}`);
|
|
101
|
+
handshakeCompleted = true;
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
|
|
82
105
|
async function checkConnection(): Promise<void> {
|
|
83
106
|
const label = `[SafeClaw]`;
|
|
84
107
|
console.log(`${label} Connecting to ${config.serviceUrl} ...`);
|
|
@@ -107,7 +130,7 @@ async function checkConnection(): Promise<void> {
|
|
|
107
130
|
export default {
|
|
108
131
|
id: 'safeclaw',
|
|
109
132
|
name: 'SafeClaw Neurosymbolic Governance',
|
|
110
|
-
version: '0.1.
|
|
133
|
+
version: '0.1.3',
|
|
111
134
|
|
|
112
135
|
register(api: PluginApi) {
|
|
113
136
|
if (!config.enabled) {
|
|
@@ -133,8 +156,16 @@ export default {
|
|
|
133
156
|
}
|
|
134
157
|
};
|
|
135
158
|
|
|
136
|
-
// Start heartbeat after connection check
|
|
137
|
-
checkConnection()
|
|
159
|
+
// Start heartbeat after connection check + handshake
|
|
160
|
+
checkConnection()
|
|
161
|
+
.then(() => performHandshake())
|
|
162
|
+
.then((ok) => {
|
|
163
|
+
if (!ok && config.failMode === 'closed') {
|
|
164
|
+
console.warn('[SafeClaw] ⚠ Handshake failed with fail-mode=closed — tool calls will be BLOCKED');
|
|
165
|
+
}
|
|
166
|
+
return sendHeartbeat();
|
|
167
|
+
})
|
|
168
|
+
.catch(() => {});
|
|
138
169
|
const heartbeatInterval = setInterval(sendHeartbeat, 30000);
|
|
139
170
|
|
|
140
171
|
// Clean shutdown: send shutdown heartbeat and clear interval
|
|
@@ -156,6 +187,10 @@ export default {
|
|
|
156
187
|
|
|
157
188
|
// THE GATE — constraint checking on every tool call
|
|
158
189
|
api.on('before_tool_call', async (event: PluginEvent, ctx: PluginContext) => {
|
|
190
|
+
if (!handshakeCompleted && config.failMode === 'closed' && config.enforcement === 'enforce') {
|
|
191
|
+
return { block: true, blockReason: 'SafeClaw handshake not completed (fail-closed)' };
|
|
192
|
+
}
|
|
193
|
+
|
|
159
194
|
const r = await post('/evaluate/tool-call', {
|
|
160
195
|
sessionId: ctx.sessionId ?? event.sessionId,
|
|
161
196
|
userId: ctx.userId ?? event.userId,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openclaw-safeclaw-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "SafeClaw Neurosymbolic Governance plugin for OpenClaw — validates AI agent actions against OWL ontologies and SHACL constraints",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|