from __future__ import annotations import os from dataclasses import dataclass, field from typing import Any @dataclass class SecretTarget: key: str label: str description: str env_var: str | None = None config_path: str | None = None required: bool = False metadata: dict[str, Any] = field(default_factory=dict) IRC_SECRET_TARGETS: list[SecretTarget] = [ SecretTarget( key="nickserv_password", label="NickServ Password", description="Password used with NickServ IDENTIFY to reserve and protect the bot's nickname", env_var="IRC_NICKSERV_PASSWORD", config_path="nickserv_password", ), SecretTarget( key="server_password", label="Server Password", description="IRC server connection password (PASS command)", env_var="IRC_SERVER_PASSWORD", config_path="password", ), SecretTarget( key="sasl_password", label="SASL Password", description="SASL authentication password for PLAIN or SCRAM mechanisms", env_var="IRC_SASL_PASSWORD", config_path="sasl_password", ), SecretTarget( key="nickserv_password_file", label="NickServ Password File", description="File path containing NickServ password (alternative to inline password)", env_var="IRC_NICKSERV_PASSWORD_FILE", config_path="nickserv_password_file", ), ] def list_secret_targets() -> list[dict[str, Any]]: return [ { "key": t.key, "label": t.label, "description": t.description, "env_var": t.env_var, "config_path": t.config_path, "required": t.required, } for t in IRC_SECRET_TARGETS ] def get_secret_target(key: str) -> dict[str, Any] | None: for t in IRC_SECRET_TARGETS: if t.key == key: return { "key": t.key, "label": t.label, "description": t.description, "env_var": t.env_var, "config_path": t.config_path, "required": t.required, } return None def audit_secrets(config: dict[str, Any]) -> list[dict[str, Any]]: findings: list[dict[str, Any]] = [] for t in IRC_SECRET_TARGETS: found_paths: list[str] = [] if t.config_path and config.get(t.config_path): found_paths.append(f"config.{t.config_path}") if t.env_var and os.environ.get(t.env_var): found_paths.append(f"env.{t.env_var}") findings.append( { "key": t.key, "label": t.label, "configured": bool(found_paths), "sources": found_paths, "required": t.required, } ) return findings