mirror of
https://github.com/n8n-io/n8n.git
synced 2026-06-03 10:17:00 +02:00
123 lines
4.0 KiB
Python
123 lines
4.0 KiB
Python
from dataclasses import dataclass
|
|
|
|
from src.env import read_bool_env, read_int_env, read_str_env
|
|
from src.errors import ConfigurationError
|
|
from src.constants import (
|
|
BUILTINS_DENY_DEFAULT,
|
|
DEFAULT_MAX_CONCURRENCY,
|
|
DEFAULT_MAX_PAYLOAD_SIZE,
|
|
DEFAULT_TASK_BROKER_URI,
|
|
DEFAULT_TASK_TIMEOUT,
|
|
DEFAULT_AUTO_SHUTDOWN_TIMEOUT,
|
|
DEFAULT_SHUTDOWN_TIMEOUT,
|
|
ENV_BLOCK_RUNNER_ENV_ACCESS,
|
|
ENV_BUILTINS_DENY,
|
|
ENV_EXTERNAL_ALLOW,
|
|
ENV_GRANT_TOKEN,
|
|
ENV_MAX_CONCURRENCY,
|
|
ENV_MAX_PAYLOAD_SIZE,
|
|
ENV_STDLIB_ALLOW,
|
|
ENV_TASK_BROKER_URI,
|
|
ENV_TASK_TIMEOUT,
|
|
ENV_AUTO_SHUTDOWN_TIMEOUT,
|
|
ENV_GRACEFUL_SHUTDOWN_TIMEOUT,
|
|
PIPE_MSG_MAX_SIZE,
|
|
)
|
|
|
|
|
|
def parse_allowlist(allowlist_str: str, list_name: str) -> set[str]:
|
|
if not allowlist_str:
|
|
return set()
|
|
|
|
modules = {
|
|
module
|
|
for raw_module in allowlist_str.split(",")
|
|
if (module := raw_module.strip())
|
|
}
|
|
|
|
if "*" in modules and len(modules) > 1:
|
|
raise ConfigurationError(
|
|
f"Wildcard '*' in {list_name} must be used alone, not with other modules. "
|
|
f"Got: {', '.join(sorted(modules))}"
|
|
)
|
|
|
|
return modules
|
|
|
|
|
|
@dataclass
|
|
class TaskRunnerConfig:
|
|
grant_token: str
|
|
task_broker_uri: str
|
|
max_concurrency: int
|
|
max_payload_size: int
|
|
task_timeout: int
|
|
auto_shutdown_timeout: int
|
|
graceful_shutdown_timeout: int
|
|
stdlib_allow: set[str]
|
|
external_allow: set[str]
|
|
builtins_deny: set[str]
|
|
env_deny: bool
|
|
|
|
@property
|
|
def is_auto_shutdown_enabled(self) -> bool:
|
|
return self.auto_shutdown_timeout > 0
|
|
|
|
@classmethod
|
|
def from_env(cls):
|
|
grant_token = read_str_env(ENV_GRANT_TOKEN, "")
|
|
if not grant_token:
|
|
raise ConfigurationError(
|
|
"Environment variable N8N_RUNNERS_GRANT_TOKEN is required"
|
|
)
|
|
|
|
task_timeout = read_int_env(ENV_TASK_TIMEOUT, DEFAULT_TASK_TIMEOUT)
|
|
if task_timeout <= 0:
|
|
raise ConfigurationError(
|
|
f"Task timeout must be positive, got {task_timeout}"
|
|
)
|
|
|
|
auto_shutdown_timeout = read_int_env(
|
|
ENV_AUTO_SHUTDOWN_TIMEOUT, DEFAULT_AUTO_SHUTDOWN_TIMEOUT
|
|
)
|
|
if auto_shutdown_timeout < 0:
|
|
raise ConfigurationError(
|
|
f"Auto shutdown timeout must be non-negative, got {auto_shutdown_timeout}"
|
|
)
|
|
|
|
graceful_shutdown_timeout = read_int_env(
|
|
ENV_GRACEFUL_SHUTDOWN_TIMEOUT, DEFAULT_SHUTDOWN_TIMEOUT
|
|
)
|
|
if graceful_shutdown_timeout <= 0:
|
|
raise ConfigurationError(
|
|
f"Graceful shutdown timeout must be positive, got {graceful_shutdown_timeout}"
|
|
)
|
|
|
|
max_payload_size = read_int_env(ENV_MAX_PAYLOAD_SIZE, DEFAULT_MAX_PAYLOAD_SIZE)
|
|
if max_payload_size > PIPE_MSG_MAX_SIZE:
|
|
raise ConfigurationError(
|
|
f"Max payload size of {max_payload_size} bytes exceeds pipe message limit of {PIPE_MSG_MAX_SIZE} bytes. Reduce {ENV_MAX_PAYLOAD_SIZE}."
|
|
)
|
|
|
|
return cls(
|
|
grant_token=grant_token,
|
|
task_broker_uri=read_str_env(ENV_TASK_BROKER_URI, DEFAULT_TASK_BROKER_URI),
|
|
max_concurrency=read_int_env(ENV_MAX_CONCURRENCY, DEFAULT_MAX_CONCURRENCY),
|
|
max_payload_size=max_payload_size,
|
|
task_timeout=task_timeout,
|
|
auto_shutdown_timeout=auto_shutdown_timeout,
|
|
graceful_shutdown_timeout=graceful_shutdown_timeout,
|
|
stdlib_allow=parse_allowlist(
|
|
read_str_env(ENV_STDLIB_ALLOW, ""), ENV_STDLIB_ALLOW
|
|
),
|
|
external_allow=parse_allowlist(
|
|
read_str_env(ENV_EXTERNAL_ALLOW, ""), ENV_EXTERNAL_ALLOW
|
|
),
|
|
builtins_deny=set(
|
|
module.strip()
|
|
for module in read_str_env(
|
|
ENV_BUILTINS_DENY, BUILTINS_DENY_DEFAULT
|
|
).split(",")
|
|
),
|
|
env_deny=read_bool_env(ENV_BLOCK_RUNNER_ENV_ACCESS, True),
|
|
)
|