Files
ops-warden/tests/test_scorecard.py
tegwick 42ca370085 feat(bootstrap): WARDEN-WP-0001 initial implementation — 42 tests passing
- LocalCA: ssh-keygen -s signing, keypair generation, cert parsing via ssh-keygen -L
- VaultCA: Vault SSH engine backend via httpx
- Inventory: YAML actor registry with ActorType, principals, TTL policy
- Scorecard: four cert-side compliance checks (prefixes, principals, no expired/stale)
- CLI: sign (cert_command interface), issue, status, scorecard, inventory subcommands
- ops-ssh-wrapper: acquire cert and exec SSH command
- Fix: principal parser stops at section headers containing ':' (Critical Options, Extensions)
- Move WARDEN-WP-0001 workplan from ops-bridge; register repo in state-hub (74df727e)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 13:27:49 +02:00

100 lines
3.0 KiB
Python

"""Tests for warden.scorecard."""
from pathlib import Path
from warden.inventory import ActorEntry, PrincipalsInventory
from warden.models import ActorType
from warden.scorecard import (
check_actor_name_prefixes,
check_all_actors_have_principals,
check_no_stale_certs,
check_no_expired_certs,
run_scorecard,
)
def make_inventory(*actors):
inv = PrincipalsInventory()
for name, atype, principals in actors:
inv.actors[name] = ActorEntry(
name=name, actor_type=atype, principals=principals, ttl_hours=24
)
return inv
# ---------------------------------------------------------------------------
# check_actor_name_prefixes
# ---------------------------------------------------------------------------
def test_prefix_check_pass():
inv = make_inventory(
("adm-bernd", ActorType.ADM, ["adm-full"]),
("agt-bridge", ActorType.AGT, ["agt-task-bridge"]),
("atm-cron", ActorType.ATM, ["atm-cron"]),
)
result = check_actor_name_prefixes(inv)
assert result.passed
def test_prefix_check_fail_bad_name():
# Bypass validate_actor_name by inserting directly
inv = PrincipalsInventory()
inv.actors["bad-name"] = ActorEntry(
name="bad-name", actor_type=ActorType.AGT, principals=["x"], ttl_hours=24
)
result = check_actor_name_prefixes(inv)
assert not result.passed
assert "bad-name" in result.detail
# ---------------------------------------------------------------------------
# check_all_actors_have_principals
# ---------------------------------------------------------------------------
def test_principals_check_pass():
inv = make_inventory(("agt-bridge", ActorType.AGT, ["agt-task-bridge"]))
result = check_all_actors_have_principals(inv)
assert result.passed
def test_principals_check_fail_empty():
inv = PrincipalsInventory()
inv.actors["agt-bridge"] = ActorEntry(
name="agt-bridge", actor_type=ActorType.AGT, principals=[], ttl_hours=24
)
result = check_all_actors_have_principals(inv)
assert not result.passed
assert "agt-bridge" in result.detail
# ---------------------------------------------------------------------------
# check_no_stale_certs
# ---------------------------------------------------------------------------
def test_no_stale_certs_nonexistent_dir():
result = check_no_stale_certs(Path("/nonexistent/state/dir"))
assert result.passed
def test_no_stale_certs_empty_dir(tmp_path):
result = check_no_stale_certs(tmp_path)
assert result.passed
def test_no_expired_certs_empty_dir(tmp_path):
result = check_no_expired_certs(tmp_path)
assert result.passed
# ---------------------------------------------------------------------------
# run_scorecard
# ---------------------------------------------------------------------------
def test_run_scorecard_clean(tmp_path):
inv = make_inventory(
("agt-bridge", ActorType.AGT, ["agt-task-bridge"]),
)
results = run_scorecard(tmp_path, inv)
assert all(r.passed for r in results)
assert len(results) == 4