@coffeexdev/openclaw-sentinel 0.1.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/LICENSE +21 -0
- package/README.md +173 -0
- package/package.json +60 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 coffeebot-agent
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# @coffeexdev/openclaw-sentinel
|
|
2
|
+
|
|
3
|
+
Secure, declarative, gateway-native background watcher plugin for OpenClaw.
|
|
4
|
+
|
|
5
|
+
## Why Sentinel
|
|
6
|
+
|
|
7
|
+
OpenClaw Sentinel runs watcher lifecycles inside the gateway using fixed strategies and declarative conditions.
|
|
8
|
+
It **does not** execute user-authored code from watcher definitions.
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- Tool registration: `sentinel_control`
|
|
13
|
+
- actions: `create`, `enable`, `disable`, `remove`, `status`, `list`
|
|
14
|
+
- Strict schema validation (`zod.strict`) + code-like field/value rejection
|
|
15
|
+
- Strategies:
|
|
16
|
+
- `http-poll`
|
|
17
|
+
- `websocket`
|
|
18
|
+
- `sse`
|
|
19
|
+
- `http-long-poll`
|
|
20
|
+
- Condition operators:
|
|
21
|
+
- `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `exists`, `absent`, `contains`, `matches`, `changed`
|
|
22
|
+
- Match mode: `all` / `any`
|
|
23
|
+
- Fire templating: substitution-only placeholders, non-Turing-complete
|
|
24
|
+
- Fire route: local internal webhook dispatch path (no outbound fire URL)
|
|
25
|
+
- Persistence: `~/.openclaw/sentinel-state.json`
|
|
26
|
+
- Resource limits and per-skill limits
|
|
27
|
+
- `allowedHosts` endpoint enforcement
|
|
28
|
+
- CLI surface: `list`, `status`, `enable`, `disable`, `audit`
|
|
29
|
+
|
|
30
|
+
## JSON Schema
|
|
31
|
+
|
|
32
|
+
Formal JSON Schema for sentinel config/watchers is available at:
|
|
33
|
+
|
|
34
|
+
- `schema/sentinel.schema.json`
|
|
35
|
+
|
|
36
|
+
You can validate a watcher config document (for example `.sentinel.json`) against this schema in CI or local tooling.
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm i @coffeexdev/openclaw-sentinel
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Quick usage
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { createSentinelPlugin } from "@coffeexdev/openclaw-sentinel";
|
|
48
|
+
|
|
49
|
+
const sentinel = createSentinelPlugin({
|
|
50
|
+
allowedHosts: ["api.github.com", "api.coingecko.com"],
|
|
51
|
+
localDispatchBase: "http://127.0.0.1:4389",
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
await sentinel.init();
|
|
55
|
+
sentinel.register({
|
|
56
|
+
registerTool(name, handler) {
|
|
57
|
+
// gateway tool registry hook
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Tool input example (`sentinel_control:create`)
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"action": "create",
|
|
67
|
+
"watcher": {
|
|
68
|
+
"id": "sentinel-poker-alert",
|
|
69
|
+
"skillId": "skills.sentinel-poker",
|
|
70
|
+
"enabled": true,
|
|
71
|
+
"strategy": "http-poll",
|
|
72
|
+
"endpoint": "https://api.github.com/events",
|
|
73
|
+
"intervalMs": 15000,
|
|
74
|
+
"match": "any",
|
|
75
|
+
"conditions": [{ "path": "type", "op": "eq", "value": "PushEvent" }],
|
|
76
|
+
"fire": {
|
|
77
|
+
"webhookPath": "/internal/sentinel/fire",
|
|
78
|
+
"eventName": "sentinel-poker_push",
|
|
79
|
+
"payloadTemplate": {
|
|
80
|
+
"watcher": "${watcher.id}",
|
|
81
|
+
"event": "${event.name}",
|
|
82
|
+
"type": "${payload.type}",
|
|
83
|
+
"ts": "${timestamp}"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"retry": { "maxRetries": 5, "baseMs": 250, "maxMs": 5000 }
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## CLI
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
openclaw-sentinel list
|
|
95
|
+
openclaw-sentinel status <watcher-id>
|
|
96
|
+
openclaw-sentinel enable <watcher-id>
|
|
97
|
+
openclaw-sentinel disable <watcher-id>
|
|
98
|
+
openclaw-sentinel audit
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### One-shot watchers
|
|
102
|
+
|
|
103
|
+
Set `"fireOnce": true` to automatically disable a watcher after its first matched event.
|
|
104
|
+
|
|
105
|
+
## Example scenarios
|
|
106
|
+
|
|
107
|
+
### Sentinel Poker feed monitoring
|
|
108
|
+
|
|
109
|
+
Watch API changes and fire internal webhook events for orchestration.
|
|
110
|
+
|
|
111
|
+
### Blockchain price watch
|
|
112
|
+
|
|
113
|
+
`http-poll` against `api.coingecko.com`, `gt/lte/changed` conditions, routed to local webhook.
|
|
114
|
+
|
|
115
|
+
### CI monitoring
|
|
116
|
+
|
|
117
|
+
`sse` or `http-long-poll` against approved CI host endpoint; fire standardized internal events.
|
|
118
|
+
|
|
119
|
+
## Security model
|
|
120
|
+
|
|
121
|
+
- No dynamic code execution from watcher definitions
|
|
122
|
+
- No dynamic imports/requires from definitions
|
|
123
|
+
- Strict input schema, unknown field rejection
|
|
124
|
+
- Code-like fields/values rejected
|
|
125
|
+
- Allowed-host enforcement on endpoints
|
|
126
|
+
- Local-only fire routing through `localDispatchBase + webhookPath`
|
|
127
|
+
- Bounded retries with backoff
|
|
128
|
+
- Global/per-skill/condition limits
|
|
129
|
+
|
|
130
|
+
## Future Improvements
|
|
131
|
+
|
|
132
|
+
1. **WebSocket/SSE resilience tuning**
|
|
133
|
+
- Improve reconnect behavior and dedupe close+error failure handling.
|
|
134
|
+
- Add stronger circuit-breaker/backoff controls under bursty failures.
|
|
135
|
+
|
|
136
|
+
2. **State persistence hardening**
|
|
137
|
+
- Add optional payload redaction or `do-not-persist-payload` mode so `lastPayload` does not store sensitive data on disk.
|
|
138
|
+
- Keep `changed` semantics while minimizing persisted sensitive fields.
|
|
139
|
+
|
|
140
|
+
3. **Dispatch integrity hardening**
|
|
141
|
+
- Add optional HMAC signing for internal webhook dispatch payloads in addition to bearer auth token support.
|
|
142
|
+
- Validate signature at receiver to prevent tampering in misconfigured local planes.
|
|
143
|
+
|
|
144
|
+
4. **Regex safety simplification and compatibility policy**
|
|
145
|
+
- Continue standardizing on `re2` with `re2-wasm` fallback.
|
|
146
|
+
- Document/centralize behavior for unsupported regex features (e.g., lookahead/backrefs).
|
|
147
|
+
|
|
148
|
+
5. **Lifecycle completeness**
|
|
149
|
+
- Add explicit `stopAll()` shutdown path in plugin lifecycle hooks for deterministic cleanup.
|
|
150
|
+
- Expand startup/reload behavior tests to ensure no orphaned watchers/timers.
|
|
151
|
+
|
|
152
|
+
6. **Test coverage expansion (priority)**
|
|
153
|
+
- Add websocket reconnection/error-dedupe tests.
|
|
154
|
+
- Add retry/backoff timing behavior tests.
|
|
155
|
+
- Add state file permission assertions and payload persistence tests.
|
|
156
|
+
- Add dispatch auth matrix tests (token on/off).
|
|
157
|
+
|
|
158
|
+
## Development
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
npm i
|
|
162
|
+
npm run lint
|
|
163
|
+
npm run test
|
|
164
|
+
npm run build
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
MIT
|
|
170
|
+
|
|
171
|
+
CI trigger probe: 2026-03-03T22:51:37Z
|
|
172
|
+
|
|
173
|
+
Push trigger probe 2026-03-03T22:56:44Z
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@coffeexdev/openclaw-sentinel",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Secure declarative gateway-native watcher plugin for OpenClaw",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"openclaw",
|
|
7
|
+
"plugin",
|
|
8
|
+
"security",
|
|
9
|
+
"sentinel",
|
|
10
|
+
"watcher"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/coffeexcoin/openclaw-sentinel.git"
|
|
16
|
+
},
|
|
17
|
+
"bin": {
|
|
18
|
+
"openclaw-sentinel": "dist/cli.js"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"README.md",
|
|
23
|
+
"LICENSE"
|
|
24
|
+
],
|
|
25
|
+
"type": "module",
|
|
26
|
+
"main": "dist/index.js",
|
|
27
|
+
"types": "dist/index.d.ts",
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsc -p tsconfig.json",
|
|
33
|
+
"test": "vitest run",
|
|
34
|
+
"lint": "tsc --noEmit",
|
|
35
|
+
"format": "oxfmt --write .",
|
|
36
|
+
"format:check": "oxfmt --check .",
|
|
37
|
+
"changeset": "changeset",
|
|
38
|
+
"version-packages": "changeset version",
|
|
39
|
+
"release": "changeset publish"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"re2-wasm": "^1.0.2",
|
|
43
|
+
"ws": "^8.18.3",
|
|
44
|
+
"zod": "^3.24.1"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@changesets/cli": "^2.29.7",
|
|
48
|
+
"@types/node": "^24.0.0",
|
|
49
|
+
"@types/ws": "^8.5.13",
|
|
50
|
+
"oxfmt": "^0.36.0",
|
|
51
|
+
"typescript": "^5.8.2",
|
|
52
|
+
"vitest": "^3.0.8"
|
|
53
|
+
},
|
|
54
|
+
"optionalDependencies": {
|
|
55
|
+
"re2": "^1.23.3"
|
|
56
|
+
},
|
|
57
|
+
"engines": {
|
|
58
|
+
"node": ">=20"
|
|
59
|
+
}
|
|
60
|
+
}
|