From cf4af0266f9c1e8cca29595ba15d74378c827f1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Abadesso?= Date: Sun, 25 Jan 2026 11:31:41 -0300 Subject: [PATCH] feat: add generic secretEnv option for provider API keys Add a flexible secretEnv option that maps environment variable names to secret file paths. The gateway wrapper reads each file at runtime and exports the env var. Example usage: secretEnv = { ZAI_API_KEY = "/run/secrets/zai_key"; OPENAI_API_KEY = "/run/secrets/openai_key"; }; This replaces the need for provider-specific options like providers.anthropic.apiKeyFile (now deprecated but still supported for backwards compatibility). Co-Authored-By: Claude Opus 4.5 --- nix/modules/home-manager/clawdbot.nix | 49 +++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/nix/modules/home-manager/clawdbot.nix b/nix/modules/home-manager/clawdbot.nix index 1b59d8b3..8d1011bc 100644 --- a/nix/modules/home-manager/clawdbot.nix +++ b/nix/modules/home-manager/clawdbot.nix @@ -187,10 +187,24 @@ let apiKeyFile = lib.mkOption { type = lib.types.str; default = ""; - description = "Path to Anthropic API key file (used to set ANTHROPIC_API_KEY)."; + description = "Path to Anthropic API key file (used to set ANTHROPIC_API_KEY). Deprecated: use secretEnv instead."; }; }; + secretEnv = lib.mkOption { + type = lib.types.attrsOf lib.types.str; + default = cfg.secretEnv; + example = { + ANTHROPIC_API_KEY = "/run/secrets/anthropic_key"; + ZAI_API_KEY = "/run/secrets/zai_key"; + }; + description = '' + Environment variables to set from secret files. + Keys are env var names, values are paths to files containing the secret. + The file contents will be read at runtime and exported as env vars. + ''; + }; + agent = { model = lib.mkOption { type = lib.types.str; @@ -743,6 +757,7 @@ let ${lib.concatStringsSep "\n" (map (entry: "export ${entry.key}=\"${entry.value}\"") pluginEnvAll)} + # Legacy: providers.anthropic.apiKeyFile (deprecated, use secretEnv) if [ -n "${inst.providers.anthropic.apiKeyFile}" ]; then if [ ! -f "${inst.providers.anthropic.apiKeyFile}" ]; then echo "Anthropic API key file not found: ${inst.providers.anthropic.apiKeyFile}" >&2 @@ -756,6 +771,22 @@ let export ANTHROPIC_API_KEY fi + # secretEnv: export env vars from secret files + ${lib.concatStringsSep "\n" (lib.mapAttrsToList (envVar: filePath: '' + if [ -n "${filePath}" ]; then + if [ ! -f "${filePath}" ]; then + echo "Secret file not found for ${envVar}: ${filePath}" >&2 + exit 1 + fi + ${envVar}="$(cat "${filePath}")" + if [ -z "''$${envVar}" ]; then + echo "Secret file is empty for ${envVar}: ${filePath}" >&2 + exit 1 + fi + export ${envVar} + fi + '') inst.secretEnv)} + exec "${gatewayPackage}/bin/clawdbot" "$@" ''; in { @@ -1072,10 +1103,24 @@ in { apiKeyFile = lib.mkOption { type = lib.types.str; default = ""; - description = "Path to Anthropic API key file (used to set ANTHROPIC_API_KEY)."; + description = "Path to Anthropic API key file (used to set ANTHROPIC_API_KEY). Deprecated: use secretEnv instead."; }; }; + secretEnv = lib.mkOption { + type = lib.types.attrsOf lib.types.str; + default = {}; + example = { + ANTHROPIC_API_KEY = "/run/secrets/anthropic_key"; + ZAI_API_KEY = "/run/secrets/zai_key"; + }; + description = '' + Environment variables to set from secret files. + Keys are env var names, values are paths to files containing the secret. + The file contents will be read at runtime and exported as env vars. + ''; + }; + routing.queue = { mode = lib.mkOption { type = lib.types.enum [ "queue" "interrupt" ];