














@@ -339,6 +339,94 @@ the config fields that accept SecretRefs.
339339}
340340```
341341</Accordion>
342+<Accordion title="password-store (`pass`)">
343+Use a small resolver wrapper when you want SecretRef ids to map directly to
344+`pass` entries. Save this as an executable in an absolute path that passes
345+your exec-provider path checks, for example
346+`/usr/local/bin/openclaw-pass-resolver`. The `#!/usr/bin/env node` shebang
347+resolves `node` from the resolver process `PATH`, so include `PATH` in
348+`passEnv`. If `pass` is not on that `PATH`, set `PASS_BIN` in the parent
349+environment and include it in `passEnv` too:
350+351+```js
352+#!/usr/bin/env node
353+const { spawnSync } = require("node:child_process");
354+355+let stdin = "";
356+process.stdin.setEncoding("utf8");
357+process.stdin.on("data", (chunk) => {
358+ stdin += chunk;
359+});
360+process.stdin.on("error", (err) => {
361+ process.stderr.write(`${err.message}\n`);
362+ process.exit(1);
363+});
364+process.stdin.on("end", () => {
365+ let request;
366+ try {
367+ request = JSON.parse(stdin || "{}");
368+ } catch (err) {
369+ process.stderr.write(`Failed to parse request: ${err.message}\n`);
370+ process.exit(1);
371+ }
372+373+ const passBin = process.env.PASS_BIN || "pass";
374+ const values = {};
375+ const errors = {};
376+377+ for (const id of request.ids ?? []) {
378+ const result = spawnSync(passBin, ["show", id], { encoding: "utf8" });
379+ if (result.status === 0) {
380+ values[id] = result.stdout.split(/\r?\n/, 1)[0] ?? "";
381+ } else {
382+ errors[id] = { message: (result.stderr || `pass exited ${result.status}`).trim() };
383+ }
384+ }
385+386+ process.stdout.write(JSON.stringify({ protocolVersion: 1, values, errors }));
387+});
388+```
389+390+Then configure the exec provider and point `apiKey` at the `pass` entry path:
391+392+```json5
393+{
394+ secrets: {
395+ providers: {
396+ pass_store: {
397+ source: "exec",
398+ command: "/usr/local/bin/openclaw-pass-resolver",
399+ passEnv: ["PATH", "HOME", "GNUPGHOME", "GPG_TTY", "PASSWORD_STORE_DIR", "PASS_BIN"],
400+ jsonOnly: true,
401+ },
402+ },
403+ },
404+ models: {
405+ providers: {
406+ openai: {
407+ baseUrl: "https://api.openai.com/v1",
408+ models: [{ id: "gpt-5", name: "gpt-5" }],
409+ apiKey: {
410+ source: "exec",
411+ provider: "pass_store",
412+ id: "openclaw/providers/openai/apiKey",
413+ },
414+ },
415+ },
416+ },
417+}
418+```
419+420+Keep the secret on the first line of the `pass` entry, or customize the
421+wrapper if you want to return the full `pass show` output instead. After
422+updating config, verify both the static audit and the exec resolver path:
423+424+```bash
425+openclaw secrets audit --check
426+openclaw secrets audit --allow-exec
427+```
428+429+</Accordion>
342430<Accordion title="sops">
343431```json5
344432{
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。