ariadne/ariadne/settings.py
codex 136caa8477
All checks were successful
Tests / Declarative: Post Actions passed: 1200
feat(hermes): search a service's own namespace for log evidence
Log evidence covered the demo namespace plus jenkins. That is right for the
common case, since CI failures happen in Jenkins agent pods, but it means a
build failure that correlates with the service itself being unhealthy carries
no trace of the service at all.

ARIADNE_HERMES_JOB_NAMESPACES maps a job to its own namespace, which is added
alongside jenkins rather than replacing it. Unmapped jobs are unchanged, and a
namespace already in the list is never duplicated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 12:32:59 -03:00

400 lines
13 KiB
Python

from __future__ import annotations
from dataclasses import dataclass
from typing import Any
from .settings_env import _env, _env_bool, _env_float, _env_int
from .settings_sections import (
_cluster_state_config,
_comms_config,
_firefly_config,
_game_stream_config,
_hermes_autotriage_config,
_hermes_code_config,
_hermes_issue_config,
_image_sweeper_config,
_jenkins_build_weather_config,
_jenkins_workspace_cleanup_config,
_keycloak_config,
_mailu_config,
_metis_config,
_nextcloud_config,
_opensearch_config,
_platform_quality_probe_config,
_portal_group_config,
_schedule_config,
_smtp_config,
_testing_triage_config,
_vault_config,
_vaultwarden_config,
_wger_config,
)
@dataclass(frozen=True)
class Settings:
app_name: str
bind_host: str
bind_port: int
ariadne_database_url: str
portal_database_url: str
portal_public_base_url: str
log_level: str
ariadne_db_pool_min: int
ariadne_db_pool_max: int
ariadne_db_connect_timeout_sec: int
ariadne_db_lock_timeout_sec: int
ariadne_db_statement_timeout_sec: int
ariadne_db_idle_in_tx_timeout_sec: int
ariadne_run_migrations: bool
keycloak_url: str
keycloak_realm: str
keycloak_client_id: str
keycloak_extra_client_ids: list[str]
keycloak_issuer: str
keycloak_jwks_url: str
keycloak_admin_url: str
keycloak_admin_realm: str
keycloak_admin_client_id: str
keycloak_admin_client_secret: str
portal_admin_users: list[str]
portal_admin_groups: list[str]
account_allowed_groups: list[str]
allowed_flag_groups: list[str]
default_user_groups: list[str]
mailu_domain: str
mailu_sync_url: str
mailu_event_min_interval_sec: float
mailu_sync_wait_timeout_sec: float
mailu_mailbox_wait_timeout_sec: float
mailu_db_host: str
mailu_db_port: int
mailu_db_name: str
mailu_db_user: str
mailu_db_password: str
mailu_host: str
mailu_default_quota: int
mailu_system_users: list[str]
mailu_system_password: str
nextcloud_namespace: str
nextcloud_pod_label: str
nextcloud_container: str
nextcloud_exec_timeout_sec: float
nextcloud_db_host: str
nextcloud_db_port: int
nextcloud_db_name: str
nextcloud_db_user: str
nextcloud_db_password: str
nextcloud_url: str
nextcloud_admin_user: str
nextcloud_admin_password: str
wger_namespace: str
wger_user_sync_wait_timeout_sec: float
wger_pod_label: str
wger_container: str
wger_admin_username: str
wger_admin_password: str
wger_admin_email: str
firefly_namespace: str
firefly_user_sync_wait_timeout_sec: float
firefly_pod_label: str
firefly_container: str
firefly_cron_base_url: str
firefly_cron_token: str
firefly_cron_timeout_sec: float
vault_namespace: str
vault_addr: str
vault_token: str
vault_k8s_role: str
vault_k8s_role_ttl: str
vault_k8s_token_reviewer_jwt: str
vault_k8s_token_reviewer_jwt_file: str
vault_oidc_discovery_url: str
vault_oidc_client_id: str
vault_oidc_client_secret: str
vault_oidc_default_role: str
vault_oidc_scopes: str
vault_oidc_user_claim: str
vault_oidc_groups_claim: str
vault_oidc_token_policies: str
vault_oidc_admin_group: str
vault_oidc_admin_policies: str
vault_oidc_dev_group: str
vault_oidc_dev_policies: str
vault_oidc_user_group: str
vault_oidc_user_policies: str
vault_oidc_redirect_uris: str
vault_oidc_bound_audiences: str
vault_oidc_bound_claims_type: str
comms_namespace: str
comms_synapse_base: str
comms_auth_base: str
comms_mas_admin_api_base: str
comms_mas_token_url: str
comms_mas_admin_client_id: str
comms_mas_admin_client_secret: str
comms_server_name: str
comms_room_alias: str
comms_room_name: str
comms_pin_message: str
comms_seeder_user: str
comms_seeder_password: str
comms_bot_user: str
comms_bot_password: str
comms_synapse_db_host: str
comms_synapse_db_port: int
comms_synapse_db_name: str
comms_synapse_db_user: str
comms_synapse_db_password: str
comms_synapse_admin_token: str
comms_timeout_sec: float
comms_guest_stale_days: int
image_sweeper_namespace: str
image_sweeper_service_account: str
image_sweeper_job_ttl_sec: int
image_sweeper_wait_timeout_sec: float
platform_quality_probe_namespace: str
platform_quality_probe_script_configmap: str
platform_quality_probe_image: str
platform_quality_probe_job_ttl_sec: int
platform_quality_probe_wait_timeout_sec: float
platform_quality_probe_pushgateway_url: str
platform_quality_probe_http_timeout_sec: int
jenkins_base_url: str
jenkins_api_user: str
jenkins_api_token: str
jenkins_api_timeout_sec: float
jenkins_workspace_namespace: str
jenkins_workspace_pvc_prefix: str
jenkins_workspace_cleanup_min_age_hours: float
jenkins_workspace_cleanup_dry_run: bool
jenkins_workspace_cleanup_max_deletions_per_run: int
testing_triage_model_url: str
testing_triage_model: str
testing_triage_model_timeout_sec: float
hermes_autotriage_enabled: bool
hermes_autotriage_job_allowlist: list[str]
hermes_autoremediation_enabled: bool
hermes_allowed_actions: list[str]
hermes_action_classifications: dict[str, str]
hermes_parameterized_jobs: list[str]
hermes_min_confidence: float
hermes_hung_build_minutes: float
hermes_max_branches: int
hermes_job_namespaces: dict
hermes_max_actions_per_incident: int
hermes_api_url: str
hermes_api_key: str
hermes_run_timeout_seconds: float
hermes_demo_namespace: str
hermes_demo_fixture_configmap: str
hermes_code_enabled: bool
hermes_code_job: str
hermes_code_owner: str
hermes_code_repo: str
hermes_code_base_branch: str
hermes_code_repos: str
hermes_code_prefixes: str
hermes_code_suffixes: str
hermes_code_base_branches: str
hermes_code_max_candidates: int
hermes_code_max_context_chars: int
hermes_code_candidate_path: str
hermes_code_allowed_prefixes: list[str]
hermes_code_allowed_suffixes: list[str]
hermes_code_max_patch_bytes: int
hermes_code_max_changed_lines: int
hermes_gitea_base_url: str
hermes_gitea_token: str
hermes_issues_enabled: bool
hermes_issue_repos: dict[str, tuple[str, str]]
hermes_issue_dedupe_scope: str
hermes_issue_max_per_tick: int
vaultwarden_namespace: str
vaultwarden_pod_label: str
vaultwarden_pod_port: int
vaultwarden_service_host: str
vaultwarden_admin_secret_name: str
vaultwarden_admin_secret_key: str
vaultwarden_admin_session_ttl_sec: float
vaultwarden_admin_rate_limit_backoff_sec: float
vaultwarden_retry_cooldown_sec: float
vaultwarden_failure_bailout: int
vaultwarden_invite_refresh_sec: float
smtp_host: str
smtp_port: int
smtp_username: str
smtp_password: str
smtp_starttls: bool
smtp_use_tls: bool
smtp_from: str
smtp_timeout_sec: float
welcome_email_enabled: bool
provision_poll_interval_sec: float
provision_retry_cooldown_sec: float
schedule_tick_sec: float
k8s_api_timeout_sec: float
vm_url: str
cluster_state_vm_timeout_sec: float
alertmanager_url: str
mailu_sync_cron: str
nextcloud_sync_cron: str
nextcloud_cron: str
nextcloud_maintenance_cron: str
vaultwarden_sync_cron: str
wger_user_sync_cron: str
wger_admin_cron: str
firefly_user_sync_cron: str
firefly_cron: str
pod_cleaner_cron: str
opensearch_prune_cron: str
image_sweeper_cron: str
vault_k8s_auth_cron: str
vault_oidc_cron: str
comms_guest_name_cron: str
comms_pin_invite_cron: str
comms_reset_room_cron: str
comms_seed_room_cron: str
keycloak_profile_cron: str
cluster_state_cron: str
cluster_state_keep: int
game_mode_node_name: str
game_mode_displace_workloads: list[dict[str, Any]]
game_mode_lease_namespace: str
game_mode_lease_name: str
game_mode_ollama_url: str
game_mode_ollama_model: str
game_mode_ollama_request_timeout_sec: float
game_mode_transition_timeout_sec: float
game_mode_poll_interval_sec: float
game_mode_hook_token: str
wolf_oidc_client_id: str
wolf_oidc_base_url: str
wolf_oidc_vault_path: str
wolf_oidc_cron: str
wolf_api_url: str
wolf_api_timeout_sec: float
wolf_gatekeeper_url: str
wolf_gatekeeper_timeout_sec: float
game_stream_firewall_unlock_ttl_sec: int
game_stream_moonlight_host: str
game_stream_user_group: str
game_stream_admin_group: str
game_stream_profile_group_prefix: str
metis_base_url: str
metis_watch_url: str
metis_timeout_sec: float
metis_sentinel_watch_cron: str
metis_token_sync_namespace: str
metis_token_sync_service_account: str
metis_token_sync_node_name: str
metis_token_sync_image: str
metis_token_sync_job_ttl_sec: int
metis_token_sync_wait_timeout_sec: float
metis_token_sync_vault_addr: str
metis_token_sync_vault_k8s_role: str
metis_k3s_token_sync_cron: str
platform_quality_suite_probe_cron: str
jenkins_build_weather_cron: str
jenkins_workspace_cleanup_cron: str
testing_triage_cron: str
hermes_autotriage_cron: str
opensearch_url: str
opensearch_limit_bytes: int
opensearch_index_patterns: str
opensearch_timeout_sec: float
metrics_path: str
@classmethod
def from_env(cls) -> "Settings":
keycloak_cfg = _keycloak_config()
portal_cfg = _portal_group_config()
mailu_cfg = _mailu_config()
smtp_cfg = _smtp_config(mailu_cfg["mailu_domain"])
nextcloud_cfg = _nextcloud_config()
wger_cfg = _wger_config()
firefly_cfg = _firefly_config()
vault_cfg = _vault_config()
comms_cfg = _comms_config()
image_cfg = _image_sweeper_config()
platform_quality_probe_cfg = _platform_quality_probe_config()
jenkins_build_weather_cfg = _jenkins_build_weather_config()
jenkins_workspace_cleanup_cfg = _jenkins_workspace_cleanup_config()
testing_triage_cfg = _testing_triage_config()
hermes_autotriage_cfg = _hermes_autotriage_config()
hermes_code_cfg = _hermes_code_config()
hermes_issue_cfg = _hermes_issue_config()
vaultwarden_cfg = _vaultwarden_config()
schedule_cfg = _schedule_config()
cluster_cfg = _cluster_state_config()
game_stream_cfg = _game_stream_config()
metis_cfg = _metis_config()
opensearch_cfg = _opensearch_config()
portal_db = _env("PORTAL_DATABASE_URL", "")
ariadne_db = _env("ARIADNE_DATABASE_URL", portal_db)
return cls(
app_name=_env("ARIADNE_APP_NAME", "ariadne"),
bind_host=_env("ARIADNE_BIND_HOST", "0.0.0.0"),
bind_port=_env_int("ARIADNE_BIND_PORT", 8080),
ariadne_database_url=ariadne_db,
portal_database_url=portal_db,
portal_public_base_url=_env("PORTAL_PUBLIC_BASE_URL", "https://bstein.dev").rstrip("/"),
log_level=_env("ARIADNE_LOG_LEVEL", "INFO"),
ariadne_db_pool_min=_env_int("ARIADNE_DB_POOL_MIN", 0),
ariadne_db_pool_max=_env_int("ARIADNE_DB_POOL_MAX", 5),
ariadne_db_connect_timeout_sec=_env_int("ARIADNE_DB_CONNECT_TIMEOUT_SEC", 5),
ariadne_db_lock_timeout_sec=_env_int("ARIADNE_DB_LOCK_TIMEOUT_SEC", 5),
ariadne_db_statement_timeout_sec=_env_int("ARIADNE_DB_STATEMENT_TIMEOUT_SEC", 30),
ariadne_db_idle_in_tx_timeout_sec=_env_int("ARIADNE_DB_IDLE_IN_TX_TIMEOUT_SEC", 10),
ariadne_run_migrations=_env_bool("ARIADNE_RUN_MIGRATIONS", "false"),
provision_poll_interval_sec=_env_float("ARIADNE_PROVISION_POLL_INTERVAL_SEC", 5.0),
provision_retry_cooldown_sec=_env_float("ARIADNE_PROVISION_RETRY_COOLDOWN_SEC", 30.0),
schedule_tick_sec=_env_float("ARIADNE_SCHEDULE_TICK_SEC", 5.0),
k8s_api_timeout_sec=_env_float("K8S_API_TIMEOUT_SEC", 5.0),
metrics_path=_env("METRICS_PATH", "/metrics"),
**keycloak_cfg,
**portal_cfg,
**mailu_cfg,
**smtp_cfg,
**nextcloud_cfg,
**wger_cfg,
**firefly_cfg,
**vault_cfg,
**comms_cfg,
**image_cfg,
**platform_quality_probe_cfg,
**jenkins_build_weather_cfg,
**jenkins_workspace_cleanup_cfg,
**testing_triage_cfg,
**hermes_autotriage_cfg,
**hermes_code_cfg,
**hermes_issue_cfg,
**vaultwarden_cfg,
**schedule_cfg,
**cluster_cfg,
**game_stream_cfg,
**metis_cfg,
**opensearch_cfg,
)
settings = Settings.from_env()