From 065f81ec24ba584a74bb44c757b59b1374e1aab7 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Fri, 21 Aug 2026 08:32:57 -0500 Subject: [PATCH] use the shared substitution namespace in go2rtc config The generator rebuilt the namespace itself from os.environ and a hardcoded /run/secrets, so it never saw environment_vars or CREDENTIALS_DIRECTORY, and str.format made any stray brace fatal. It now installs the FRIGATE_ names from environment_vars and substitutes streams the same way every other field does. --- .../rootfs/usr/local/go2rtc/create_config.py | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/docker/main/rootfs/usr/local/go2rtc/create_config.py b/docker/main/rootfs/usr/local/go2rtc/create_config.py index 70cb744f13..0dee057ff5 100644 --- a/docker/main/rootfs/usr/local/go2rtc/create_config.py +++ b/docker/main/rootfs/usr/local/go2rtc/create_config.py @@ -3,13 +3,12 @@ import json import os import sys -from pathlib import Path from typing import Any from ruamel.yaml import YAML sys.path.insert(0, "/opt/frigate") -from frigate.config.env import substitute_frigate_vars +from frigate.config.env import apply_config_env_vars, substitute_frigate_vars from frigate.const import ( BIRDSEYE_PIPE, LIBAVFORMAT_VERSION_MAJOR, @@ -25,15 +24,6 @@ sys.path.remove("/opt/frigate") yaml = YAML() -FRIGATE_ENV_VARS = {k: v for k, v in os.environ.items() if k.startswith("FRIGATE_")} -# read docker secret files as env vars too -if os.path.isdir("/run/secrets"): - for secret_file in os.listdir("/run/secrets"): - if secret_file.startswith("FRIGATE_"): - FRIGATE_ENV_VARS[secret_file] = ( - Path(os.path.join("/run/secrets", secret_file)).read_text().strip() - ) - config_file = find_config_file() try: @@ -47,6 +37,20 @@ try: except FileNotFoundError: config: dict[str, Any] = {} +# No validator runs here, so install environment_vars ourselves. FRIGATE_ +# names only: anything else lands in os.environ, where the exec gate reads +# GO2RTC_ALLOW_ARBITRARY_EXEC. +config_env_vars = config.get("environment_vars") +apply_config_env_vars( + { + key: value + for key, value in config_env_vars.items() + if str(key).startswith("FRIGATE_") + } + if isinstance(config_env_vars, dict) + else {} +) + go2rtc_config: dict[str, Any] = config.get("go2rtc", {}) # Need to enable CORS for go2rtc so the frigate integration / card work automatically @@ -113,7 +117,7 @@ for name in list(go2rtc_config.get("streams", {})): if isinstance(stream, str): try: - formatted_stream = stream.format(**FRIGATE_ENV_VARS) + formatted_stream = substitute_frigate_vars(stream) if is_restricted_go2rtc_source(formatted_stream): print( f"[ERROR] Stream '{name}' uses a restricted source (echo/expr/exec) which is disabled by default for security. " @@ -122,7 +126,7 @@ for name in list(go2rtc_config.get("streams", {})): del go2rtc_config["streams"][name] continue go2rtc_config["streams"][name] = formatted_stream - except KeyError as e: + except ValueError as e: print( "[ERROR] Invalid substitution found, see https://docs.frigate.video/configuration/restream#advanced-restream-configurations for more info." ) @@ -132,7 +136,7 @@ for name in list(go2rtc_config.get("streams", {})): filtered_streams = [] for i, stream_item in enumerate(stream): try: - formatted_stream = stream_item.format(**FRIGATE_ENV_VARS) + formatted_stream = substitute_frigate_vars(stream_item) if is_restricted_go2rtc_source(formatted_stream): print( f"[ERROR] Stream '{name}' item {i + 1} uses a restricted source (echo/expr/exec) which is disabled by default for security. " @@ -141,7 +145,7 @@ for name in list(go2rtc_config.get("streams", {})): continue filtered_streams.append(formatted_stream) - except KeyError as e: + except ValueError as e: print( "[ERROR] Invalid substitution found, see https://docs.frigate.video/configuration/restream#advanced-restream-configurations for more info." )