From 5086b88a00747d05181f84f15fb3b1b8e18e66a7 Mon Sep 17 00:00:00 2001 From: macm1 Date: Mon, 23 Feb 2026 05:28:32 +0300 Subject: [PATCH] feat: Add gateway environment variables support - Add 'gateway_env_vars' configuration option to addon config - Parse semicolon-separated KEY=VALUE pairs from add-on options - Export environment variables to gateway process at startup - Store parsed env vars in openclaw.json (gateway.env) Allows users to pass custom environment variables to the gateway via Home Assistant add-on configuration, e.g.: gateway_env_vars: 'SERVICE_API_KEY=123;SERVICE2_API=1231' These variables are exported to the gateway process and can be used for API authentication, feature flags, or other configuration needs. --- openclaw_assistant/config.yaml | 6 ++++ openclaw_assistant/oc_config_helper.py | 44 +++++++++++++++++++++++--- openclaw_assistant/run.sh | 24 +++++++++++++- 3 files changed, 68 insertions(+), 6 deletions(-) diff --git a/openclaw_assistant/config.yaml b/openclaw_assistant/config.yaml index 013b2fc..3b99056 100644 --- a/openclaw_assistant/config.yaml +++ b/openclaw_assistant/config.yaml @@ -88,6 +88,11 @@ options: # (can affect Telegram API polling in some HAOS/VM setups). force_ipv4_dns: false + # Environment variables to pass to the gateway (semicolon-separated key=value pairs) + # Example: "SERVICE_API=123;SERVICE2_API=1231" + # These will be exported as environment variables when running the gateway + gateway_env_vars: "" + schema: timezone: str @@ -109,3 +114,4 @@ schema: enable_openai_api: bool? allow_insecure_auth: bool? force_ipv4_dns: bool? + gateway_env_vars: str? diff --git a/openclaw_assistant/oc_config_helper.py b/openclaw_assistant/oc_config_helper.py index d87c0f3..3bfbd44 100644 --- a/openclaw_assistant/oc_config_helper.py +++ b/openclaw_assistant/oc_config_helper.py @@ -57,7 +57,7 @@ def set_gateway_setting(key, value): return write_config(cfg) -def apply_gateway_settings(mode: str, bind_mode: str, port: int, enable_openai_api: bool, allow_insecure_auth: bool): +def apply_gateway_settings(mode: str, bind_mode: str, port: int, enable_openai_api: bool, allow_insecure_auth: bool, env_vars: str = ""): """ Apply gateway settings to OpenClaw config. @@ -67,6 +67,7 @@ def apply_gateway_settings(mode: str, bind_mode: str, port: int, enable_openai_a port: Port number to listen on (must be 1-65535) enable_openai_api: Enable OpenAI-compatible Chat Completions endpoint allow_insecure_auth: Allow insecure HTTP authentication + env_vars: Semicolon-separated environment variables (e.g., "VAR1=value1;VAR2=value2") """ # Validate gateway mode if mode not in ["local", "remote"]: @@ -112,6 +113,7 @@ def apply_gateway_settings(mode: str, bind_mode: str, port: int, enable_openai_a current_port = gateway.get("port", 18789) current_openai_api = chat_completions.get("enabled", False) current_insecure = control_ui.get("allowInsecureAuth", False) + current_env_vars = gateway.get("env", {}) changes = [] @@ -135,6 +137,37 @@ def apply_gateway_settings(mode: str, bind_mode: str, port: int, enable_openai_a control_ui["allowInsecureAuth"] = allow_insecure_auth changes.append(f"allowInsecureAuth: {current_insecure} -> {allow_insecure_auth}") + # Parse and apply environment variables + new_env_vars = {} + if env_vars.strip(): + try: + # Parse semicolon-separated key=value pairs + pairs = env_vars.split(';') + for pair in pairs: + pair = pair.strip() + if not pair: + continue + if '=' not in pair: + print(f"WARN: Invalid env var format '{pair}' (missing '=')") + continue + key, value = pair.split('=', 1) + key = key.strip() + value = value.strip() + if not key: + print(f"WARN: Invalid env var key (empty)") + continue + new_env_vars[key] = value + except Exception as e: + print(f"ERROR: Failed to parse environment variables: {e}") + return False + + if new_env_vars != current_env_vars: + gateway["env"] = new_env_vars + if new_env_vars: + changes.append(f"env: {len(new_env_vars)} variables") + else: + changes.append("env: cleared") + if changes: if write_config(cfg): print(f"INFO: Updated gateway settings: {', '.join(changes)}") @@ -143,7 +176,7 @@ def apply_gateway_settings(mode: str, bind_mode: str, port: int, enable_openai_a print("ERROR: Failed to write config") return False else: - print(f"INFO: Gateway settings already correct (mode={mode}, bind={bind_mode}, port={port}, chatCompletions={enable_openai_api}, allowInsecureAuth={allow_insecure_auth})") + print(f"INFO: Gateway settings already correct (mode={mode}, bind={bind_mode}, port={port}, chatCompletions={enable_openai_api}, allowInsecureAuth={allow_insecure_auth}, env vars={len(current_env_vars)})") return True @@ -156,15 +189,16 @@ def main(): cmd = sys.argv[1] if cmd == "apply-gateway-settings": - if len(sys.argv) != 7: - print("Usage: oc_config_helper.py apply-gateway-settings ") + if len(sys.argv) < 7: + print("Usage: oc_config_helper.py apply-gateway-settings [env_vars]") sys.exit(1) mode = sys.argv[2] bind_mode = sys.argv[3] port = int(sys.argv[4]) enable_openai_api = sys.argv[5].lower() == "true" allow_insecure_auth = sys.argv[6].lower() == "true" - success = apply_gateway_settings(mode, bind_mode, port, enable_openai_api, allow_insecure_auth) + env_vars = sys.argv[7] if len(sys.argv) > 7 else "" + success = apply_gateway_settings(mode, bind_mode, port, enable_openai_api, allow_insecure_auth, env_vars) sys.exit(0 if success else 1) elif cmd == "get": diff --git a/openclaw_assistant/run.sh b/openclaw_assistant/run.sh index fa89a64..b9ef6b7 100644 --- a/openclaw_assistant/run.sh +++ b/openclaw_assistant/run.sh @@ -52,6 +52,7 @@ GATEWAY_PORT=$(jq -r '.gateway_port // 18789' "$OPTIONS_FILE") ENABLE_OPENAI_API=$(jq -r '.enable_openai_api // false' "$OPTIONS_FILE") ALLOW_INSECURE_AUTH=$(jq -r '.allow_insecure_auth // false' "$OPTIONS_FILE") FORCE_IPV4_DNS=$(jq -r '.force_ipv4_dns // false' "$OPTIONS_FILE") +GW_ENV_VARS=$(jq -r '.gateway_env_vars // empty' "$OPTIONS_FILE") export TZ="$TZNAME" @@ -147,6 +148,27 @@ export PNPM_HOME="${PERSISTENT_NODE_GLOBAL}/pnpm" mkdir -p "$PNPM_HOME" export PATH="${PNPM_HOME}:${PATH}" +# Export gateway environment variables from add-on config +# These are user-defined variables that should be available to the gateway process +if [ -n "$GW_ENV_VARS" ]; then + echo "INFO: Setting gateway environment variables from add-on config..." + IFS=';' read -ra ENV_VARS <<< "$GW_ENV_VARS" + for var in "${ENV_VARS[@]}"; do + var=$(echo "$var" | xargs) # trim whitespace + if [ -z "$var" ]; then + continue + fi + if [[ ! "$var" =~ ^[A-Za-z_][A-Za-z0-9_]*=.*$ ]]; then + echo "WARN: Invalid environment variable format: '$var' (skipping)" + continue + fi + export "$var" + # Extract key for logging (don't log values for security) + key="${var%%=*}" + echo "INFO: Exported gateway env var: $key" + done +fi + # ------------------------------------------------------------------------------ # Persist Linuxbrew/Homebrew across Docker image rebuilds # Homebrew installs to /home/linuxbrew/.linuxbrew/ which is ephemeral. @@ -353,7 +375,7 @@ fi if [ -f "$OPENCLAW_CONFIG_PATH" ]; then if [ -f "$HELPER_PATH" ]; then - if ! python3 "$HELPER_PATH" apply-gateway-settings "$GATEWAY_MODE" "$GATEWAY_BIND_MODE" "$GATEWAY_PORT" "$ENABLE_OPENAI_API" "$ALLOW_INSECURE_AUTH"; then + if ! python3 "$HELPER_PATH" apply-gateway-settings "$GATEWAY_MODE" "$GATEWAY_BIND_MODE" "$GATEWAY_PORT" "$ENABLE_OPENAI_API" "$ALLOW_INSECURE_AUTH" "$GW_ENV_VARS"; then rc=$? echo "ERROR: Failed to apply gateway settings via oc_config_helper.py (exit code ${rc})." echo "ERROR: Gateway configuration may be incorrect; aborting startup."