backend: remove __main__ runner; typing: fix mypy across core and routes; tooling: use uv for pytest in pre-commit; security: narrow broad except in config; mypy: relax untyped decorator check for backend.app.main

This commit is contained in:
William Valentin
2025-09-15 01:25:25 -07:00
parent be520c14e9
commit b544399f9c
9 changed files with 69 additions and 58 deletions

View File

@@ -9,7 +9,7 @@ import configparser
import re
from dataclasses import dataclass, field
from enum import Enum
from typing import List, Optional
from typing import Any, Dict, List, Optional
class UnitType(Enum):
@@ -46,6 +46,11 @@ class UnitFileInfo:
conflicts: List[str] = field(default_factory=list)
class CaseConfigParser(configparser.ConfigParser):
def optionxform(self, optionstr: str) -> str:
return str(optionstr)
class SystemdUnitFile:
"""
Parser and validator for systemd unit files.
@@ -306,7 +311,7 @@ class SystemdUnitFile:
}
# Service types and their requirements
SERVICE_TYPES = {
SERVICE_TYPES: Dict[str, Dict[str, List[str]]] = {
"simple": {"required": ["ExecStart"], "conflicts": ["BusName", "Type=forking"]},
"exec": {"required": ["ExecStart"], "conflicts": ["BusName"]},
"forking": {"recommended": ["PIDFile"], "conflicts": ["BusName"]},
@@ -320,11 +325,10 @@ class SystemdUnitFile:
"""Initialize with either content string or file path."""
self.content = content or ""
self.file_path = file_path
self.config = configparser.ConfigParser(
self.config = CaseConfigParser(
interpolation=None, allow_no_value=True, delimiters=("=",)
)
self.config.optionxform = lambda optionstr: str(optionstr) # Preserve case
self._parse_errors = []
self._parse_errors: List[ValidationError] = []
if content:
self._parse_content(content)
@@ -419,7 +423,7 @@ class SystemdUnitFile:
def validate(self) -> List[ValidationError]:
"""Validate the unit file and return list of errors/warnings."""
errors = self._parse_errors.copy()
errors: List[ValidationError] = self._parse_errors.copy()
# Check for basic structure
if not self.config.sections():
@@ -443,7 +447,7 @@ class SystemdUnitFile:
def _validate_section(self, section: str) -> List[ValidationError]:
"""Validate a specific section."""
errors = []
errors: List[ValidationError] = []
# Check if section is known
if section not in self.COMMON_SECTIONS:
@@ -477,7 +481,7 @@ class SystemdUnitFile:
self, section: str, key: str, value: str
) -> List[ValidationError]:
"""Validate specific key-value pairs."""
errors = []
errors: List[ValidationError] = []
# Service-specific validations
if section == "Service":
@@ -574,7 +578,7 @@ class SystemdUnitFile:
def _validate_unit_type(self, unit_type: UnitType) -> List[ValidationError]:
"""Perform type-specific validation."""
errors = []
errors: List[ValidationError] = []
if unit_type == UnitType.SERVICE:
errors.extend(self._validate_service())
@@ -589,13 +593,14 @@ class SystemdUnitFile:
def _validate_service(self) -> List[ValidationError]:
"""Validate service-specific requirements."""
errors = []
errors: List[ValidationError] = []
if not self.config.has_section("Service"):
return errors
service_type = self.config.get("Service", "Type", fallback="simple")
type_config = self.SERVICE_TYPES.get(service_type, {})
tmp = self.SERVICE_TYPES.get(service_type)
type_config: Dict[str, List[str]] = {} if tmp is None else tmp
# Check required keys
for required_key in type_config.get("required", []):
@@ -648,7 +653,7 @@ class SystemdUnitFile:
def _validate_timer(self) -> List[ValidationError]:
"""Validate timer-specific requirements."""
errors = []
errors: List[ValidationError] = []
if not self.config.has_section("Timer"):
return errors
@@ -678,7 +683,7 @@ class SystemdUnitFile:
def _validate_socket(self) -> List[ValidationError]:
"""Validate socket-specific requirements."""
errors = []
errors: List[ValidationError] = []
if not self.config.has_section("Socket"):
return errors
@@ -709,7 +714,7 @@ class SystemdUnitFile:
def _validate_mount(self) -> List[ValidationError]:
"""Validate mount-specific requirements."""
errors = []
errors: List[ValidationError] = []
if not self.config.has_section("Mount"):
return errors
@@ -755,7 +760,9 @@ class SystemdUnitFile:
for section in self.config.sections():
lines.append(f"[{section}]")
for key in self.config.options(section):
value = self.config.get(section, key)
from typing import cast
value = cast(Optional[str], self.config.get(section, key))
if value is None:
lines.append(key)
else:
@@ -796,7 +803,7 @@ class SystemdUnitFile:
return self.config.options(section)
def create_unit_file(unit_type: UnitType, **kwargs) -> SystemdUnitFile:
def create_unit_file(unit_type: UnitType, **kwargs: Any) -> SystemdUnitFile:
"""
Create a new unit file of the specified type with basic structure.