@arloraccoon/openclaw-vaultwarden-plugin 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/README.md +326 -0
- package/dist/index.mjs +752 -0
- package/dist/secret-resolver.mjs +228 -0
- package/openclaw.plugin.json +89 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
# OpenClaw Vaultwarden plugin
|
|
2
|
+
|
|
3
|
+
Package: `@arloraccoon/openclaw-vaultwarden-plugin`
|
|
4
|
+
|
|
5
|
+
Metadata-safe Bitwarden-compatible Vaultwarden tools for OpenClaw, with
|
|
6
|
+
explicitly opt-in login-item mutations.
|
|
7
|
+
|
|
8
|
+
## Scope
|
|
9
|
+
|
|
10
|
+
The plugin always exposes these metadata-safe tools:
|
|
11
|
+
|
|
12
|
+
- `vaultwarden_status`
|
|
13
|
+
- `vaultwarden_search`
|
|
14
|
+
- `vaultwarden_get_item`
|
|
15
|
+
- `vaultwarden_list_folders`
|
|
16
|
+
- `vaultwarden_list_collections`
|
|
17
|
+
|
|
18
|
+
When `allowMutations: true` is explicitly configured, it additionally exposes:
|
|
19
|
+
|
|
20
|
+
- `vaultwarden_create_item`
|
|
21
|
+
- `vaultwarden_update_item`
|
|
22
|
+
- `vaultwarden_delete_item`
|
|
23
|
+
|
|
24
|
+
Item reads remain metadata-only. Passwords, usernames, TOTP seeds, notes, and
|
|
25
|
+
custom-field values are not returned by these tools. The separate SecretRef
|
|
26
|
+
resolver remains the supported exact-field path for supplying a password or
|
|
27
|
+
hidden/text custom field to OpenClaw.
|
|
28
|
+
|
|
29
|
+
## Prerequisites
|
|
30
|
+
|
|
31
|
+
Install the Bitwarden CLI (`bw`) and configure it for the target server before
|
|
32
|
+
starting OpenClaw:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
bw config server https://vaultwarden.example.com
|
|
36
|
+
bw login
|
|
37
|
+
bw unlock
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The plugin reads the existing CLI session through `BW_SESSION`; it never asks
|
|
41
|
+
the model for a master password. For isolated testing, set
|
|
42
|
+
`BITWARDENCLI_APPDATA_DIR` to a temporary directory and do not point it at a
|
|
43
|
+
production CLI profile.
|
|
44
|
+
|
|
45
|
+
## Install the plugin
|
|
46
|
+
|
|
47
|
+
Run either method on the machine that runs the OpenClaw Gateway. Set `REPO_DIR`
|
|
48
|
+
to the absolute path of your local checkout; the example below uses a generic
|
|
49
|
+
placeholder and does not assume a particular home-directory layout.
|
|
50
|
+
|
|
51
|
+
### Method 1: Link the local checkout
|
|
52
|
+
|
|
53
|
+
Best for local development. OpenClaw loads the built files directly from the
|
|
54
|
+
checkout, so each source change can be built in place:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
REPO_DIR="/path/to/openclaw-vaultwarden-plugin"
|
|
58
|
+
cd "$REPO_DIR"
|
|
59
|
+
git pull --ff-only
|
|
60
|
+
pnpm install --frozen-lockfile
|
|
61
|
+
pnpm build
|
|
62
|
+
openclaw plugins install "$REPO_DIR" --link --force --accept-capabilities
|
|
63
|
+
openclaw config validate
|
|
64
|
+
openclaw plugins reload vaultwarden --accept-capabilities
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Re-run `pnpm build` after source changes, then reload the plugin. `--link`
|
|
68
|
+
requires an existing local path and cannot be combined with a `git:` source.
|
|
69
|
+
|
|
70
|
+
### Method 2: Install from a local Git URL
|
|
71
|
+
|
|
72
|
+
This installs a committed Git snapshot into OpenClaw's managed plugin
|
|
73
|
+
directory; it is not linked to the checkout:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
REPO_DIR="/path/to/openclaw-vaultwarden-plugin"
|
|
77
|
+
openclaw plugins install "git:file://${REPO_DIR}" --force --accept-capabilities
|
|
78
|
+
openclaw config validate
|
|
79
|
+
openclaw plugins reload vaultwarden --accept-capabilities
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
OpenClaw clones committed Git contents for this method. This repository ignores
|
|
83
|
+
generated `dist/` files, which contain the entry points required by
|
|
84
|
+
`openclaw.plugin.json`; building `dist/` in the checkout does not add it to the
|
|
85
|
+
Git clone. Therefore, use this method only with a prepared Git source that
|
|
86
|
+
includes those built entry points. For this checkout's normal local build and
|
|
87
|
+
install workflow, use Method 1.
|
|
88
|
+
|
|
89
|
+
For either method, `--force` permits replacing an existing installation and
|
|
90
|
+
`--accept-capabilities` accepts the capabilities declared by this plugin.
|
|
91
|
+
Review the plugin capabilities before accepting them.
|
|
92
|
+
|
|
93
|
+
The plugin registers read-only tools by default. To also register the
|
|
94
|
+
single-item create, update, and soft-delete tools, set the JSON boolean after
|
|
95
|
+
installing the version whose schema includes the option:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
openclaw config set plugins.entries.vaultwarden.config.allowMutations true --strict-json
|
|
99
|
+
openclaw config validate
|
|
100
|
+
openclaw plugins reload vaultwarden --accept-capabilities
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
This changes only the `allowMutations` leaf and preserves other plugin
|
|
104
|
+
settings, including a configured session SecretRef. Leave it unset or `false`
|
|
105
|
+
to keep mutation tools unavailable. Keep `vaultwarden` in the existing
|
|
106
|
+
`plugins.allow` inventory if the Gateway uses an explicit plugin allowlist.
|
|
107
|
+
|
|
108
|
+
### Troubleshooting the local install
|
|
109
|
+
|
|
110
|
+
- **`allowMutations` is unknown or rejected:** Build and install the latest
|
|
111
|
+
checkout first, then set the option and validate again. An older installed
|
|
112
|
+
plugin schema cannot validate a field introduced by the newer source.
|
|
113
|
+
- **Plugin entry or extension path is missing:** Check that
|
|
114
|
+
`$REPO_DIR/dist/index.mjs` exists and
|
|
115
|
+
rerun the `plugins install` command above. For a linked install, confirm
|
|
116
|
+
`~/.openclaw/extensions/vaultwarden` resolves to the maintained checkout.
|
|
117
|
+
Prefer the supported installer to manually editing the plugin registry or
|
|
118
|
+
creating/removing extension paths.
|
|
119
|
+
- **Plugin does not load after install:** Run `openclaw config validate` and
|
|
120
|
+
`openclaw plugins doctor`; inspect the reported plugin ID and path, rebuild
|
|
121
|
+
with `pnpm build`, then run `openclaw plugins reload vaultwarden
|
|
122
|
+
--accept-capabilities`.
|
|
123
|
+
- **Install appears stuck or asks about local-source trust/capabilities:** Run
|
|
124
|
+
the command in an interactive terminal and respond to any prompt. The flags
|
|
125
|
+
above handle the normal source/capability confirmations; do not start a
|
|
126
|
+
second install while the first is still running.
|
|
127
|
+
- **Config validation reports an active agent database lease:** Another
|
|
128
|
+
OpenClaw process is using the state database. Check Gateway/process status
|
|
129
|
+
and wait for any concurrent update or maintenance operation to finish
|
|
130
|
+
before retrying validation; do not delete SQLite, WAL, or SHM files.
|
|
131
|
+
- **Vault session is expired:** Follow
|
|
132
|
+
[Session expiry and recovery](#session-expiry-and-recovery). Refresh the
|
|
133
|
+
configured provider rather than putting a session token in chat or replacing
|
|
134
|
+
the plugin config object.
|
|
135
|
+
|
|
136
|
+
## OpenClaw configuration
|
|
137
|
+
|
|
138
|
+
The plugin accepts:
|
|
139
|
+
|
|
140
|
+
- `adapter`: currently `cli`
|
|
141
|
+
- `sessionEnv`: alternate environment variable name for the CLI session
|
|
142
|
+
- `session`: an OpenClaw SecretRef or session string; SecretRef is recommended
|
|
143
|
+
- `timeoutSeconds`: command timeout, from 1 to 120 seconds
|
|
144
|
+
- `maxResults`: result bound, from 1 to 100 items
|
|
145
|
+
- `allowMutations`: explicitly register create/update/soft-delete tools; defaults to `false`
|
|
146
|
+
|
|
147
|
+
Example:
|
|
148
|
+
|
|
149
|
+
```json
|
|
150
|
+
{
|
|
151
|
+
"adapter": "cli",
|
|
152
|
+
"timeoutSeconds": 15,
|
|
153
|
+
"maxResults": 20
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
The read-only default is preserved unless the operator opts in:
|
|
158
|
+
|
|
159
|
+
```json5
|
|
160
|
+
{
|
|
161
|
+
plugins: {
|
|
162
|
+
entries: {
|
|
163
|
+
vaultwarden: {
|
|
164
|
+
enabled: true,
|
|
165
|
+
config: {
|
|
166
|
+
allowMutations: true
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Controlled login-item mutations
|
|
175
|
+
|
|
176
|
+
The optional mutation tools operate on one Bitwarden **login** item at a time.
|
|
177
|
+
Create accepts a name plus optional username, password, URIs, notes, folder,
|
|
178
|
+
collections, and custom fields (hidden by default). Update fetches the exact
|
|
179
|
+
item internally, changes only supplied fields, and preserves other existing
|
|
180
|
+
item data; it rejects non-login items. Set a field to `null` or an array to
|
|
181
|
+
`[]` to clear/replace it where supported. Update/delete require a strict item
|
|
182
|
+
UUID. Delete is a reversible Bitwarden soft-delete only; it requires a
|
|
183
|
+
`confirmation` argument exactly matching `itemId`. Permanent deletion and bulk
|
|
184
|
+
operations are not exposed.
|
|
185
|
+
|
|
186
|
+
Mutation payloads are encoded and sent to the local `bw` process over stdin,
|
|
187
|
+
not placed in command-line arguments. They are excluded from this plugin's
|
|
188
|
+
audit events and tool results; CLI output and errors are redacted before they
|
|
189
|
+
reach the caller. OpenClaw's own tool-call transcript/logging policy is a
|
|
190
|
+
separate boundary. Enable mutations only for agents/workflows authorized to
|
|
191
|
+
change the vault. Install and tests do not change production vault data.
|
|
192
|
+
|
|
193
|
+
For a managed deployment, keep the session out of plaintext config and chat by
|
|
194
|
+
using an OpenClaw SecretRef:
|
|
195
|
+
|
|
196
|
+
```json5
|
|
197
|
+
{
|
|
198
|
+
plugins: {
|
|
199
|
+
entries: {
|
|
200
|
+
vaultwarden: {
|
|
201
|
+
enabled: true,
|
|
202
|
+
config: {
|
|
203
|
+
session: {
|
|
204
|
+
source: "env",
|
|
205
|
+
provider: "default",
|
|
206
|
+
id: "BW_SESSION"
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
The session is resolved only at the CLI boundary and is never returned by a
|
|
216
|
+
tool or written to audit events. File and exec SecretRefs are also supported.
|
|
217
|
+
|
|
218
|
+
## SecretRef provider integration
|
|
219
|
+
|
|
220
|
+
The plugin also declares a managed OpenClaw exec SecretRef provider preset
|
|
221
|
+
named vaultwarden. OpenClaw runs the packaged Node resolver; the resolver
|
|
222
|
+
reads only exact Bitwarden item IDs and returns only the explicitly selected
|
|
223
|
+
field. It does not make secrets available through the plugin's read-only
|
|
224
|
+
tools.
|
|
225
|
+
|
|
226
|
+
Use a SecretRef ID in one of these forms:
|
|
227
|
+
|
|
228
|
+
- `<item-uuid>/password` — the login password only
|
|
229
|
+
- `<item-uuid>/field/<custom-field-name>` — exactly one custom text or hidden
|
|
230
|
+
field with that exact name
|
|
231
|
+
|
|
232
|
+
For example, a supported service credential can refer to
|
|
233
|
+
`{ "source": "exec", "provider": "vaultwarden", "id":
|
|
234
|
+
"123e4567-e89b-42d3-a456-426614174000/password" }`. Replace the example UUID
|
|
235
|
+
with the selected item's UUID. Username, TOTP, notes, boolean fields, and
|
|
236
|
+
ambiguous/missing field names are not supported.
|
|
237
|
+
|
|
238
|
+
The resolver uses `BW_SESSION` when OpenClaw explicitly passes it. Otherwise it
|
|
239
|
+
reads `~/.openclaw/secrets/vaultwarden-session`, the private file created by
|
|
240
|
+
`openclaw vaultwarden`; set `VAULTWARDEN_SESSION_FILE` to override that path.
|
|
241
|
+
The file must be a regular, non-symlink file owned by the OpenClaw user with
|
|
242
|
+
no group/other permissions (normally mode 0600) and contain one non-empty
|
|
243
|
+
session value. Ensure bw is installed and configured for the intended
|
|
244
|
+
Vaultwarden profile on the OpenClaw host.
|
|
245
|
+
|
|
246
|
+
Requests are bounded, item IDs are strict UUIDs, and `bw get item <UUID>` is
|
|
247
|
+
spawned without a shell, with a timeout and output limit. Resolver failures
|
|
248
|
+
are generic and do not include CLI output or secret values. SecretRef
|
|
249
|
+
materialization is handled by OpenClaw for supported config fields; this does
|
|
250
|
+
not add a Git credential handoff.
|
|
251
|
+
|
|
252
|
+
OpenClaw classifies private/self-hosted Git installs as unverified provenance,
|
|
253
|
+
even when the installed commit matches the reviewed branch. This describes
|
|
254
|
+
the source channel, not a content scan. Keep `vaultwarden` in the existing
|
|
255
|
+
`plugins.allow` inventory when using an explicit plugin allowlist; do not
|
|
256
|
+
replace the inventory with only this plugin. The allowlist pins which plugin
|
|
257
|
+
IDs may load, but does not turn a private Git source into an official install.
|
|
258
|
+
|
|
259
|
+
## Session expiry and recovery
|
|
260
|
+
|
|
261
|
+
Vault access tools never attempt to unlock the vault or prompt for the master
|
|
262
|
+
password. If the Bitwarden CLI reports an expired or unavailable session, the
|
|
263
|
+
tool returns a recovery instruction tailored to the configured session source
|
|
264
|
+
instead of raw CLI output. For a local file SecretRef, refresh that same file
|
|
265
|
+
with `openclaw vaultwarden --session-file <path>` (only for a single-value file
|
|
266
|
+
provider); the default command path is not necessarily the path your SecretRef
|
|
267
|
+
uses. For an environment, exec, or store SecretRef, update the value at its
|
|
268
|
+
provider and retry—the command writes a local file and does not update those
|
|
269
|
+
providers. For an unconfigured session, the command creates the default local
|
|
270
|
+
session file, which must then be configured as a file SecretRef. The helper logs
|
|
271
|
+
in only when the CLI is unauthenticated, prompts locally to unlock, and writes
|
|
272
|
+
the token atomically with mode `0600`. Never copy a session value into chat.
|
|
273
|
+
|
|
274
|
+
For a local operator setup that does not depend on Gateway environment
|
|
275
|
+
inheritance, run this from the OpenClaw host:
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
openclaw vaultwarden --session-file ~/.openclaw/secrets/vaultwarden-session
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
The command runs `bw unlock --raw` with the password prompt attached to the
|
|
282
|
+
terminal, stores only the resulting session in a `0600` file, and prints no
|
|
283
|
+
token. Configure the OpenClaw file provider and plugin reference using the
|
|
284
|
+
values it prints, then reload the plugin. The model still cannot unlock the
|
|
285
|
+
vault or receive the session token.
|
|
286
|
+
|
|
287
|
+
## Security model
|
|
288
|
+
|
|
289
|
+
- Interactive reads expose metadata only; optional writes are disabled by default.
|
|
290
|
+
- Writes are single-item login operations, exact-ID scoped, and never hard-delete.
|
|
291
|
+
- Secret payloads travel to the CLI over stdin; this plugin excludes them from audit events and tool results. Host transcript/logging policy is separate.
|
|
292
|
+
- Metadata-first output with field-level redaction.
|
|
293
|
+
- Generic errors; CLI output and credentials are not copied into errors.
|
|
294
|
+
- Structured audit events contain only operation and success/error outcome.
|
|
295
|
+
- The separate SecretRef resolver retrieves only the explicitly selected
|
|
296
|
+
password or custom text/hidden field for OpenClaw's supported secret
|
|
297
|
+
resolution path; it does not expose values through plugin tools or logs.
|
|
298
|
+
- The plugin does not unlock the vault. Vault mutation tools are registered only
|
|
299
|
+
when `allowMutations` is exactly `true`.
|
|
300
|
+
|
|
301
|
+
## Local verification
|
|
302
|
+
|
|
303
|
+
From this standalone repository:
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
pnpm test
|
|
307
|
+
pnpm typecheck
|
|
308
|
+
pnpm lint
|
|
309
|
+
pnpm build
|
|
310
|
+
bash tests/test-integration.sh
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
The disposable integration gate also requires Docker, `bw`, `curl`, OpenSSL,
|
|
314
|
+
and Playwright Chromium. Install Chromium once with
|
|
315
|
+
`pnpm exec playwright install chromium`.
|
|
316
|
+
|
|
317
|
+
The integration script creates a disposable volatile Vaultwarden container,
|
|
318
|
+
waits for `/alive` and `/api/config`, provisions a synthetic account through
|
|
319
|
+
the disposable web registration flow, verifies isolated CLI login/unlock,
|
|
320
|
+
metadata reads, opt-in create/update/soft-delete, and SecretRef retrieval, then
|
|
321
|
+
removes the container and temporary CLI profile on exit. This is a
|
|
322
|
+
mixed-capability plugin (tools, auth CLI, and
|
|
323
|
+
SecretRef provider); OpenClaw's `plugins validate` authoring check is for
|
|
324
|
+
`defineToolPlugin`-style tool-only packages. Use the installed runtime smoke
|
|
325
|
+
test for this package instead of treating that tool-only check as a generic
|
|
326
|
+
plugin validity gate.
|