mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-19 04:57:26 +00:00
feat(secrets): finalize mode rename and validated exec docs
This commit is contained in:
committed by
Peter Steinberger
parent
ba2eb583c0
commit
06290b49b2
@@ -2423,7 +2423,7 @@ Validation:
|
||||
filemain: {
|
||||
source: "file",
|
||||
path: "~/.openclaw/secrets.json",
|
||||
mode: "jsonPointer",
|
||||
mode: "json",
|
||||
timeoutMs: 5000,
|
||||
},
|
||||
vault: {
|
||||
@@ -2443,8 +2443,9 @@ Validation:
|
||||
|
||||
Notes:
|
||||
|
||||
- `file` provider supports `mode: "jsonPointer"` and `mode: "raw"` (`id` must be `"value"` in raw mode).
|
||||
- `exec` provider requires an absolute `command` path and uses protocol payloads on stdin/stdout.
|
||||
- `file` provider supports `mode: "json"` and `mode: "singleValue"` (`id` must be `"value"` in singleValue mode).
|
||||
- `exec` provider requires an absolute non-symlink `command` path and uses protocol payloads on stdin/stdout.
|
||||
- `exec` child environment is minimal by default; pass required variables explicitly with `passEnv`.
|
||||
- Secret refs are resolved at activation time into an in-memory snapshot, then request paths read the snapshot only.
|
||||
|
||||
---
|
||||
|
||||
@@ -87,7 +87,7 @@ Define providers under `secrets.providers`:
|
||||
filemain: {
|
||||
source: "file",
|
||||
path: "~/.openclaw/secrets.json",
|
||||
mode: "jsonPointer", // or "raw"
|
||||
mode: "json", // or "singleValue"
|
||||
},
|
||||
vault: {
|
||||
source: "exec",
|
||||
@@ -119,13 +119,14 @@ Define providers under `secrets.providers`:
|
||||
### File provider
|
||||
|
||||
- Reads local file from `path`.
|
||||
- `mode: "jsonPointer"` expects JSON object payload and resolves `id` as pointer.
|
||||
- `mode: "raw"` expects ref id `"value"` and returns file contents.
|
||||
- `mode: "json"` expects JSON object payload and resolves `id` as pointer.
|
||||
- `mode: "singleValue"` expects ref id `"value"` and returns file contents.
|
||||
- Path must pass ownership/permission checks.
|
||||
|
||||
### Exec provider
|
||||
|
||||
- Runs configured absolute binary path, no shell.
|
||||
- `command` must point to a regular file (not a symlink).
|
||||
- Supports timeout, no-output timeout, output byte limits, env allowlist, and trusted dirs.
|
||||
- Request payload (stdin):
|
||||
|
||||
@@ -149,6 +150,121 @@ Optional per-id errors:
|
||||
}
|
||||
```
|
||||
|
||||
## Validated exec integration examples
|
||||
|
||||
The patterns below were validated end-to-end with `openclaw secrets audit --json` and `unresolvedRefCount=0`.
|
||||
|
||||
### 1Password (`op`)
|
||||
|
||||
1. Create a wrapper script (non-symlink command path):
|
||||
|
||||
```bash
|
||||
cat >/usr/local/libexec/openclaw/op-openai.sh <<'SH'
|
||||
#!/bin/sh
|
||||
exec /opt/homebrew/bin/op read 'op://Personal/OpenClaw QA API Key/password'
|
||||
SH
|
||||
chmod 700 /usr/local/libexec/openclaw/op-openai.sh
|
||||
```
|
||||
|
||||
2. Configure provider + ref:
|
||||
|
||||
```json5
|
||||
{
|
||||
secrets: {
|
||||
providers: {
|
||||
onepassword_openai: {
|
||||
source: "exec",
|
||||
command: "/usr/local/libexec/openclaw/op-openai.sh",
|
||||
passEnv: ["HOME"],
|
||||
jsonOnly: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
models: {
|
||||
providers: {
|
||||
openai: {
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
apiKey: { source: "exec", provider: "onepassword_openai", id: "value" },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### HashiCorp Vault CLI
|
||||
|
||||
1. Wrapper script:
|
||||
|
||||
```bash
|
||||
cat >/usr/local/libexec/openclaw/vault-openai.sh <<'SH'
|
||||
#!/bin/sh
|
||||
exec /opt/homebrew/opt/vault/bin/vault kv get -field=OPENAI_API_KEY secret/openclaw
|
||||
SH
|
||||
chmod 700 /usr/local/libexec/openclaw/vault-openai.sh
|
||||
```
|
||||
|
||||
2. Provider + ref:
|
||||
|
||||
```json5
|
||||
{
|
||||
secrets: {
|
||||
providers: {
|
||||
vault_openai: {
|
||||
source: "exec",
|
||||
command: "/usr/local/libexec/openclaw/vault-openai.sh",
|
||||
passEnv: ["VAULT_ADDR", "VAULT_TOKEN"],
|
||||
jsonOnly: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
models: {
|
||||
providers: {
|
||||
openai: {
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
apiKey: { source: "exec", provider: "vault_openai", id: "value" },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### `sops`
|
||||
|
||||
1. Wrapper script:
|
||||
|
||||
```bash
|
||||
cat >/usr/local/libexec/openclaw/sops-openai.sh <<'SH'
|
||||
#!/bin/sh
|
||||
exec /opt/homebrew/bin/sops -d --extract '["providers"]["openai"]["apiKey"]' /path/to/secrets.enc.json
|
||||
SH
|
||||
chmod 700 /usr/local/libexec/openclaw/sops-openai.sh
|
||||
```
|
||||
|
||||
2. Provider + ref:
|
||||
|
||||
```json5
|
||||
{
|
||||
secrets: {
|
||||
providers: {
|
||||
sops_openai: {
|
||||
source: "exec",
|
||||
command: "/usr/local/libexec/openclaw/sops-openai.sh",
|
||||
passEnv: ["SOPS_AGE_KEY_FILE"],
|
||||
jsonOnly: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
models: {
|
||||
providers: {
|
||||
openai: {
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
apiKey: { source: "exec", provider: "sops_openai", id: "value" },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## In-scope fields (v1)
|
||||
|
||||
### `~/.openclaw/openclaw.json`
|
||||
@@ -231,11 +347,17 @@ Findings include:
|
||||
|
||||
Interactive helper that:
|
||||
|
||||
- configures `secrets.providers` first (`env`/`file`/`exec`, add/edit/remove)
|
||||
- lets you select secret-bearing fields in `openclaw.json`
|
||||
- captures SecretRef details (`source`, `provider`, `id`)
|
||||
- runs preflight resolution
|
||||
- can apply immediately
|
||||
|
||||
Helpful modes:
|
||||
|
||||
- `openclaw secrets configure --providers-only`
|
||||
- `openclaw secrets configure --skip-provider-setup`
|
||||
|
||||
`configure` apply defaults to:
|
||||
|
||||
- scrub matching static creds from `auth-profiles.json` for targeted providers
|
||||
|
||||
Reference in New Issue
Block a user