← Back to Plugins
Tools

Secret Delivery

golem-workers By golem-workers ⭐ 1 stars 👁 112 views ▲ 0 votes

Owner-scoped OpenClaw plugin for delivering Secret Store entries to SSH files without exposing values

GitHub

Install

openclaw plugins install --link

Configuration Example

{"ok":true,"host":"deploy@example.org","file":"/etc/example-app/runtime.env","field":"CLIENT_SECRET","mode":"0600","verified":true}

README

# OpenClaw Secret Delivery

Deliver an existing OpenClaw Secret Store entry to a remote file over SSH, without returning its value to the agent or putting it in command arguments.

One plugin for many applications: choose the secret, configured SSH host, destination file, and optional environment field. Adding another destination is configuration, not application-specific code.

**Requirements:** OpenClaw **2026.9.4** (tested version), Node.js 22.12+, OpenSSH client on the Gateway host, and Python 3 on a POSIX SSH server. Later OpenClaw versions require compatibility verification. Windows SSH servers, binary secrets, interactive SSH authentication, custom SSH ports and automatic service restarts are not supported in v0.1.0.

## Install

Run on the host that owns the OpenClaw Secret Store:

```sh
git clone --branch v0.1.0 https://github.com/golem-workers/openclaw-secret-delivery.git
cd openclaw-secret-delivery
npm test
openclaw plugins install --link "$PWD" --accept-capabilities --force
```

`--force` acknowledges the local source in the tested OpenClaw installer; it does not disable security scanning. Respect any installation-policy rejection. A linked installation needs this directory to remain in place. Keep it at a reviewed tag or commit, not an automatically changing branch. No build or `npm install` is needed: executable JavaScript is included and OpenClaw supplies its own SDK at plugin load time.

The CLI becomes available in a new command invocation. To expose the agent tool, restart the Gateway at a suitable time and allow the optional `secret_deliver` tool under your existing tool policy. Do not replace your current allowlists or disable approval controls. The tool additionally requires OpenClaw's trusted `senderIsOwner` context; missing or false owner context is denied.

## Configure a destination

Example only — substitute your host, existing SSH key and directory:

```sh
openclaw config set 'plugins.entries.secret-delivery.config' '{"targets":[{"host":"deploy@example.org","identityFile":"/home/operator/.ssh/app_ed25519","directories":["/etc/example-app"]}]}' --strict-json
```

This replaces **this plugin's** configuration. When adding targets later, preserve existing entries. See [configuration example](examples/plugin-config.json).

The remote directory must already exist, be writable by the SSH account, and be protected from untrusted writers. Provision the SSH host key through your normal trusted process. `StrictHostKeyChecking=yes` and `BatchMode=yes` are mandatory; the plugin will not accept an unknown host key or prompt for a password. It uses an explicit identity file and does not forward SSH agents or application credentials through the subprocess environment.

Store the secret through OpenClaw's existing masked entry or supported secret provisioning process. Do not paste values into chat, scripts, Git, command arguments, or this configuration.

## Deliver or rotate an environment field

```sh
openclaw secret-deliver \
  --secret MY_APP_CLIENT_SECRET \
  --host deploy@example.org \
  --file /etc/example-app/runtime.env \
  --field CLIENT_SECRET
```

Example result (no value):

```json
{"ok":true,"host":"deploy@example.org","file":"/etc/example-app/runtime.env","field":"CLIENT_SECRET","mode":"0600","verified":true}
```

The field is replaced, unrelated lines are retained, and the destination is written atomically with mode `0600`. Re-run the same command after rotating the stored secret. Read-back verification compares the complete written file inside the remote process; it does **not** prove the credential is valid or the application has reloaded it.

Field mode supports **single-line systemd EnvironmentFile assignments**, not a general shell/dotenv parser. Do not use it on files with multiline assignments. Do not `source` its output as a shell script: shell interpolation and systemd parsing have different rules. Newline/NUL values are rejected in field mode. Secret values are UTF-8 strings, not arbitrary bytes.

## Deliver a whole file

```sh
openclaw secret-deliver \
  --secret MY_APP_CONFIG \
  --host deploy@example.org \
  --file /etc/example-app/credentials.json
```

**Omitting `--field` replaces the entire file.** Multiline string values are supported in this mode. Neither mode creates parent directories, reloads services, or validates application-specific syntax.

## Agent integration

See [the agent guide](docs/agents.md) for task boundaries, tool arguments, CLI fallback and status reporting. [Русская инструкция](docs/README.ru.md) is also available.

```json
{"secret":"MY_APP_CLIENT_SECRET","host":"deploy@example.org","file":"/etc/example-app/runtime.env","field":"CLIENT_SECRET"}
```

## How it works

1. Validate the destination against operator-authored configuration, before resolving anything.
2. Resolve `{source: "store", provider: configuredDefaultOrDefault, id: secretName}` through the public `openclaw/plugin-sdk/secret-ref-runtime` SDK, inside the native plugin process.
3. Invoke SSH with a fixed remote Python program; send the path, field and value in JSON through stdin, not shell interpolation.
4. Lock the destination, create a temporary file, fsync, atomically rename, and verify contents and `0600` permissions.
5. Return only status and destination metadata. Remote stderr and unexpected stdout are not relayed.

This is not an export/read-secret tool, an egress-sentinel workaround, or a separate vault. Credentials necessarily exist in plaintext briefly in the authorized plugin, SSH pipe and remote writer memory. See [security and limitations](SECURITY.md).

## Development and verification

```sh
npm test
npm pack --dry-run
```

Tests use dummy secrets and local temporary files. They do not contact a real Secret Store or SSH server. The [CI template](docs/ci.workflow.yml) runs the test suite on Node.js 22 and 24 and checks package contents. Hosted CI is not enabled in the initial release: the publishing GitHub credential lacked the `workflow` scope. An operator with workflow permissions can install this file as `.github/workflows/ci.yml`. Neither the template nor local tests independently validate a live Secret Store. The original implementation was installed with OpenClaw 2026.9.4 and successfully delivered a production credential; public packaging and registration are covered by local tests. No independent security audit is claimed.

Executable sources live in `dist/`; there is no generated build stage. Contributions should keep the SDK import confined to `dist/index.js`, so registration and transport tests stay independent of a live Gateway.

## Releases and updates

Use a reviewed tagged release, inspect changes, run tests, then update the linked checkout and restart the Gateway when appropriate. A rollback means checking out the previous tag; it does not undo a remote file write or restore a previous secret. Release archives and SHA-256 checksums are published on GitHub. This project is MIT-licensed; see [LICENSE](LICENSE).
tools

Comments

Sign in to leave a comment

Loading comments...