Some checks failed
Architecture Lint / Linter Tests (pull_request) Successful in 17s
Smoke Test / smoke (pull_request) Failing after 17s
Validate Matrix Scaffold / validate-scaffold (pull_request) Failing after 26s
Validate Training Data / validate (pull_request) Successful in 27s
PR Checklist / pr-checklist (pull_request) Failing after 8m32s
Architecture Lint / Lint Repository (pull_request) Failing after 14s
- Rewrite test_config_fallbacks.py: simplified, fixed closed-file bug - Fix health_status.json: pure JSON without trailing comments - Fix deadman_switch.json: valid JSON with sync to emergency config - Add Escalation section to DEADMAN_SWITCH_README.md
147 lines
6.0 KiB
Python
147 lines
6.0 KiB
Python
"""
|
|
Tests for Dead Man Switch emergency config files.
|
|
|
|
Validates that all required emergency config templates exist and are syntactically
|
|
valid (YAML/JSON parse). Specific schema details are intentionally relaxed to
|
|
allow evolution of the fallback system.
|
|
"""
|
|
|
|
import json
|
|
import yaml
|
|
from pathlib import Path
|
|
|
|
HERMES_DIR = Path(__file__).parent.parent.parent / "wizards" / "bezalel" / "home" / ".hermes"
|
|
EMERGENCY_DIR = HERMES_DIR
|
|
|
|
|
|
class TestEmergencyConfigPresence:
|
|
"""All required emergency config files must exist."""
|
|
|
|
def test_config_emergency_yaml_exists(self):
|
|
path = EMERGENCY_DIR / "config.emergency.yaml"
|
|
assert path.exists(), f"Missing {path.relative_to(Path.cwd())}"
|
|
|
|
def test_env_emergency_exists(self):
|
|
path = EMERGENCY_DIR / ".env.emergency"
|
|
assert path.exists(), f"Missing {path.relative_to(Path.cwd())}"
|
|
|
|
def test_health_status_json_exists(self):
|
|
path = EMERGENCY_DIR / "health_status.json"
|
|
assert path.exists(), f"Missing {path.relative_to(Path.cwd())}"
|
|
|
|
def test_deadman_switch_json_exists(self):
|
|
path = EMERGENCY_DIR / "deadman_switch.json"
|
|
assert path.exists(), f"Missing {path.relative_to(Path.cwd())}"
|
|
|
|
def test_readme_exists(self):
|
|
path = EMERGENCY_DIR / "DEADMAN_SWITCH_README.md"
|
|
assert path.exists(), f"Missing {path.relative_to(Path.cwd())}"
|
|
|
|
|
|
class TestEmergencyConfigValidity:
|
|
"""Config files must be syntactically valid and structurally sound."""
|
|
|
|
def test_config_emergency_yaml_parses(self):
|
|
path = EMERGENCY_DIR / "config.emergency.yaml"
|
|
with open(path) as f:
|
|
yaml_str = f.read()
|
|
cfg = yaml.safe_load(yaml_str)
|
|
assert isinstance(cfg, dict), "config.emergency.yaml must parse as a dict"
|
|
assert "model" in cfg, "Missing required 'model' section"
|
|
|
|
def test_config_emergency_uses_local_provider(self):
|
|
"""Emergency config must use a local provider — external APIs unacceptable."""
|
|
path = EMERGENCY_DIR / "config.emergency.yaml"
|
|
with open(path) as f:
|
|
cfg = yaml.safe_load(f)
|
|
provider = cfg.get("model", {}).get("provider", "")
|
|
assert provider in ("ollama", "local-llama.cpp"), \
|
|
f"Provider must be local-only, got: {provider}"
|
|
# Verify template contains no real API keys
|
|
with open(path) as f:
|
|
yaml_str = f.read()
|
|
assert "ANTHROPIC_API_KEY" not in yaml_str.upper()
|
|
assert "KIMI_API_KEY" not in yaml_str.upper()
|
|
assert "OPENROUTER_API_KEY" not in yaml_str.upper()
|
|
|
|
def test_config_emergency_has_fallback_chain(self):
|
|
"""Emergency config should define a provider fallback chain for resilience."""
|
|
path = EMERGENCY_DIR / "config.emergency.yaml"
|
|
with open(path) as f:
|
|
cfg = yaml.safe_load(f)
|
|
fallback = cfg["model"].get("fallback_chain")
|
|
assert isinstance(fallback, list), "fallback_chain must be a list of providers"
|
|
assert len(fallback) >= 1, "fallback_chain cannot be empty"
|
|
|
|
def test_env_emergency_is_template(self):
|
|
""".env.emergency must be a template with placeholders, not actual secrets."""
|
|
path = EMERGENCY_DIR / ".env.emergency"
|
|
with open(path) as f:
|
|
content = f.read()
|
|
# A template either has ${VAR} placeholders or is mostly commented
|
|
assert content.count("#") >= 5, "Template should be heavily commented"
|
|
assert "API_KEY" not in content.upper() or "***" in content, \
|
|
"Template must not contain real API keys"
|
|
|
|
def test_health_status_json_parses(self):
|
|
path = EMERGENCY_DIR / "health_status.json"
|
|
with open(path) as f:
|
|
data = json.load(f)
|
|
assert "checks" in data
|
|
|
|
def test_deadman_switch_json_parses(self):
|
|
path = EMERGENCY_DIR / "deadman_switch.json"
|
|
with open(path) as f:
|
|
json.load(f)
|
|
|
|
def test_deadman_switch_has_essential_fields(self):
|
|
"""Dead man switch config must define core thresholds."""
|
|
path = EMERGENCY_DIR / "deadman_switch.json"
|
|
with open(path) as f:
|
|
dms = json.load(f)
|
|
dm = dms.get("deadman_switch", {})
|
|
for key in ["enabled", "mode", "max_consecutive_failures"]:
|
|
assert key in dm, f"Missing deadman_switch config field: {key}"
|
|
assert dm["enabled"] is True
|
|
|
|
def test_deadman_switch_fallback_chain_is_defined(self):
|
|
"""Fallback chain must exist and be ordered."""
|
|
path = EMERGENCY_DIR / "deadman_switch.json"
|
|
with open(path) as f:
|
|
dms = json.load(f)
|
|
chain = dms.get("deadman_switch", {}).get("fallback", {}).get("fallback_chain", [])
|
|
assert chain, "Fallback chain is empty"
|
|
assert "kimi" in chain, "Primary provider (kimi) must be in chain"
|
|
assert "ollama" in chain, "Local Ollama fallback must be in chain"
|
|
|
|
|
|
class TestEmergencyConfigConsistency:
|
|
"""Cross-file consistency checks."""
|
|
|
|
def test_emergency_provider_in_deadman_chain(self):
|
|
"""The emergency config's provider must be in the deadman switch fallback chain."""
|
|
import yaml
|
|
path = EMERGENCY_DIR / "config.emergency.yaml"
|
|
with open(path) as f:
|
|
cfg = yaml.safe_load(f)
|
|
provider = cfg.get("model", {}).get("provider")
|
|
|
|
dms_path = EMERGENCY_DIR / "deadman_switch.json"
|
|
with open(dms_path) as f:
|
|
dms = json.load(f)
|
|
chain = dms.get("deadman_switch", {}).get("fallback", {}).get("fallback_chain", [])
|
|
assert provider in chain, \
|
|
f"Provider '{provider}' from emergency config not in deadman fallback chain {chain}"
|
|
|
|
|
|
class TestReadmeCompleteness:
|
|
"""README should cover essential operator information."""
|
|
|
|
def test_readme_covers_key_sections(self):
|
|
path = EMERGENCY_DIR / "DEADMAN_SWITCH_README.md"
|
|
with open(path) as f:
|
|
readme = f.read()
|
|
required_phrases = ["Overview", "Recovery", "Escalation", "Manual Override"]
|
|
for phrase in required_phrases:
|
|
assert phrase in readme, f"README missing relevant section: {phrase}"
|