feat(services): config schemas for the rest of the registry + textarea base64 transport
- Declarative config_schema on RDP, Telnet, MySQL, Redis, SMTP, SMTP_Relay matching the keys each service already reads at compose time. - TODO marker on the 19 services that accept service_cfg but never read it, so future contributors know where to plug schemas in. - Wizard base64-wraps all textarea values at INI emit (DeckyFleet buildIni); validate_cfg detects the b64: sentinel and decodes back to UTF-8. Plain raw strings still pass through for direct API submitters. - HTTPS image entrypoint accepts PEM content or path in TLS_CERT/TLS_KEY: detects a BEGIN header, writes content to /opt/tls/, and re-exports the on-disk path so server.py keeps reading paths. - Tests cover schema/compose alignment for each new service plus textarea base64 round-trip (incl. UTF-8) and HTTPS PEM end-to-end.
This commit is contained in:
@@ -1,8 +1,16 @@
|
||||
import base64
|
||||
import binascii
|
||||
from abc import ABC, abstractmethod
|
||||
from dataclasses import asdict, dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any, Literal
|
||||
|
||||
# Sentinel prefix used by the deploy wizard to ship multi-line textarea values
|
||||
# through ConfigParser without relying on its multi-line continuation syntax.
|
||||
# Plain raw values without the prefix are accepted as-is so direct API
|
||||
# submitters (PUT /…/services/{svc}/config) keep working with raw strings.
|
||||
TEXTAREA_B64_PREFIX = "b64:"
|
||||
|
||||
FieldType = Literal["string", "password", "int", "bool", "textarea", "enum"]
|
||||
|
||||
|
||||
@@ -105,8 +113,18 @@ class BaseService(ABC):
|
||||
|
||||
def _coerce(spec: ServiceConfigField, raw: Any) -> Any:
|
||||
t = spec.type
|
||||
if t in ("string", "password", "textarea"):
|
||||
if t in ("string", "password"):
|
||||
return str(raw)
|
||||
if t == "textarea":
|
||||
s = str(raw)
|
||||
if s.startswith(TEXTAREA_B64_PREFIX):
|
||||
try:
|
||||
return base64.b64decode(s[len(TEXTAREA_B64_PREFIX):], validate=True).decode("utf-8")
|
||||
except (binascii.Error, UnicodeDecodeError) as e:
|
||||
raise ConfigValidationError(
|
||||
f"{spec.key}: malformed {TEXTAREA_B64_PREFIX} payload"
|
||||
) from e
|
||||
return s
|
||||
if t == "int":
|
||||
try:
|
||||
return int(raw)
|
||||
|
||||
Reference in New Issue
Block a user