52 lines
1.7 KiB
Python
52 lines
1.7 KiB
Python
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import json
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
from jsonschema import validate
|
|
|
|
from app.file_pipeline import DetectorManifest
|
|
from app.rules import RuleBundle
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class ActiveConfig:
|
|
version: int
|
|
document: dict[str, Any]
|
|
rules: RuleBundle
|
|
detector: DetectorManifest
|
|
|
|
@property
|
|
def rules_version(self) -> str:
|
|
return self.rules.version
|
|
|
|
|
|
def canonical_config(document: dict[str, Any]) -> bytes:
|
|
return json.dumps(document, ensure_ascii=False, sort_keys=True, separators=(",", ":")).encode()
|
|
|
|
|
|
def validate_config(
|
|
document: dict[str, Any], artifacts: Path
|
|
) -> tuple[RuleBundle, DetectorManifest, bytes]:
|
|
schema = json.loads((artifacts / "config.schema.json").read_text(encoding="utf-8"))
|
|
validate(document, schema)
|
|
task = document["task"]
|
|
if not task["heartbeat_sec"] < task["lease_sec"] < task["execution_deadline_sec"]:
|
|
raise ValueError("heartbeat_sec < lease_sec < execution_deadline_sec is required")
|
|
rules_ref = document["rules_bundle_ref"]
|
|
rules = RuleBundle.load(
|
|
artifacts / "rules" / rules_ref / "rules.yaml",
|
|
artifacts / "rules" / "rules.schema.json",
|
|
)
|
|
detector = DetectorManifest.load(artifacts / "detector-manifest.json")
|
|
enabled = set(document["file_policy"]["enabled_mime_types"])
|
|
if not enabled <= detector.supported:
|
|
raise ValueError("file policy is not a detector manifest subset")
|
|
if document["file_policy"]["max_size_bytes"] > detector.max_size:
|
|
raise ValueError("file policy exceeds detector hard limit")
|
|
digest = hashlib.sha256(canonical_config(document)).digest()
|
|
return rules, detector, digest
|