From 30d95b879870b8353a3fe1ee5585a8e3a5580b2f Mon Sep 17 00:00:00 2001 From: macm1 Date: Mon, 23 Feb 2026 05:40:32 +0300 Subject: [PATCH] refactor: use YAML map for gateway environment variables instead of string parsing Benefits: - More idiomatic configuration format for Home Assistant add-ons - config.yaml: Change default from empty string to empty YAML map - config.yaml: Update schema type from str? to map(str)? - config.yaml: Improve documentation to explain YAML map usage - run.sh: Parse JSON object from jq using to_entries instead of semicolon splitting - oc_config_helper.py: Accept JSON string and parse as dict instead of semicolon-separated values - Better error handling for invalid JSON - Cleaner and more maintainable parsing logic This allows users to configure environment variables more naturally: gateway_env_vars: OPENAI_API_KEY: sk-abc123 SERVICE_URL: https://api.example.com --- openclaw_assistant/config.yaml | 21 +++++++----- openclaw_assistant/oc_config_helper.py | 44 ++++++++++++-------------- openclaw_assistant/run.sh | 16 +++++----- 3 files changed, 41 insertions(+), 40 deletions(-) diff --git a/openclaw_assistant/config.yaml b/openclaw_assistant/config.yaml index f9421ca..d37c5d9 100644 --- a/openclaw_assistant/config.yaml +++ b/openclaw_assistant/config.yaml @@ -88,15 +88,20 @@ 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) - # Format: "KEY1=value1;KEY2=value2" (semicolon-separated, no spaces around '=') + # Environment variables to pass to the gateway as a YAML map + # These variables are exported to the gateway process at startup # Examples: - # - API keys: "OPENAI_API_KEY=sk-abc123;ANTHROPIC_API_KEY=claude-key" - # - Service URLs: "SERVICE_URL=https://api.example.com;LOG_LEVEL=debug" - # - Features: "FEATURE_FLAG_X=1;FEATURE_FLAG_Y=0" + # API keys: + # OPENAI_API_KEY: "sk-abc123" + # ANTHROPIC_API_KEY: "claude-key" + # Service URLs: + # SERVICE_URL: "https://api.example.com" + # LOG_LEVEL: "debug" + # Feature flags: + # FEATURE_FLAG_X: "1" + # FEATURE_FLAG_Y: "0" # Limits: max 50 variables, max key length 255 chars, max value length 10000 chars - # Note: Values may contain special characters; they are not shell-escaped - gateway_env_vars: "" + gateway_env_vars: {} schema: @@ -119,4 +124,4 @@ schema: enable_openai_api: bool? allow_insecure_auth: bool? force_ipv4_dns: bool? - gateway_env_vars: str? + gateway_env_vars: map(str)? diff --git a/openclaw_assistant/oc_config_helper.py b/openclaw_assistant/oc_config_helper.py index aecc798..08bdd5b 100644 --- a/openclaw_assistant/oc_config_helper.py +++ b/openclaw_assistant/oc_config_helper.py @@ -62,7 +62,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, env_vars: str = ""): +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. @@ -72,7 +72,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") + env_vars: JSON string with environment variables as key-value pairs (e.g., '{"VAR1":"value1","VAR2":"value2"}') """ # Validate gateway mode if mode not in ["local", "remote"]: @@ -142,23 +142,20 @@ 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 + # Parse and apply environment variables from JSON new_env_vars = {} - if env_vars.strip(): + if env_vars.strip() and env_vars != "{}": 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() + # Parse JSON object containing environment variables + parsed = json.loads(env_vars) + if not isinstance(parsed, dict): + print(f"ERROR: Environment variables must be a JSON object (dict), got {type(parsed).__name__}") + return False + + for key, value in parsed.items(): + # Ensure value is string + if not isinstance(value, str): + value = str(value) # Validate key format if not key: @@ -176,18 +173,17 @@ def apply_gateway_settings(mode: str, bind_mode: str, port: int, enable_openai_a print(f"ERROR: Environment variable '{key}' value too large (max {MAX_ENV_VAR_VALUE_SIZE} chars)") return False - # Warn about duplicate keys - if key in new_env_vars: - print(f"WARN: Environment variable '{key}' appears multiple times; using last value") - new_env_vars[key] = value # Enforce limit on total variables if len(new_env_vars) > MAX_ENV_VARS: print(f"ERROR: Too many environment variables ({len(new_env_vars)}), max {MAX_ENV_VARS}") return False + except json.JSONDecodeError as e: + print(f"ERROR: Failed to parse environment variables JSON: {e}") + return False except Exception as e: - print(f"ERROR: Failed to parse environment variables: {e}") + print(f"ERROR: Failed to process environment variables: {e}") return False if new_env_vars != current_env_vars: @@ -220,14 +216,14 @@ def main(): if cmd == "apply-gateway-settings": if len(sys.argv) < 7: - print("Usage: oc_config_helper.py apply-gateway-settings [env_vars]") + print("Usage: oc_config_helper.py apply-gateway-settings [env_vars_json]") 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" - env_vars = sys.argv[7] if len(sys.argv) > 7 else "" + 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) diff --git a/openclaw_assistant/run.sh b/openclaw_assistant/run.sh index 76a4cc0..b1fb12b 100644 --- a/openclaw_assistant/run.sh +++ b/openclaw_assistant/run.sh @@ -52,7 +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") +GW_ENV_VARS=$(jq -c '.gateway_env_vars // {}' "$OPTIONS_FILE") export TZ="$TZNAME" @@ -150,22 +150,22 @@ 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 +if [ "$GW_ENV_VARS" != "{}" ] && [ -n "$GW_ENV_VARS" ]; then echo "INFO: Setting gateway environment variables from add-on config..." env_count=0 max_env_vars=50 max_var_name_size=255 + # Parse JSON object and export each key=value pair while IFS='=' read -r key value; do - # Skip empty lines + # Skip empty lines and trim whitespace + key=$(echo "$key" | xargs) + value=$(echo "$value" | xargs) + if [ -z "$key" ]; then continue fi - # Trim whitespace - key=$(echo "$key" | xargs) - value=$(echo "$value" | xargs) - # Validate variable name format if ! [[ "$key" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]]; then echo "WARN: Invalid environment variable name: '$key' (must start with letter/underscore, skip)" @@ -187,7 +187,7 @@ if [ -n "$GW_ENV_VARS" ]; then export "$key=$value" ((env_count++)) echo "INFO: Exported gateway env var: $key" - done < <(echo "$GW_ENV_VARS" | tr ';' '\n') + done < <(echo "$GW_ENV_VARS" | jq -r 'to_entries[] | "\(.key)=\(.value)"') if [ $env_count -gt 0 ]; then echo "INFO: Successfully exported $env_count gateway environment variable(s)"