@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 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.