ForcePilot/backend/package/yuxi/channels/adapters/irc/secret_contract.py

98 lines
2.8 KiB
Python
Raw Normal View History

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