sched: require proven ownership at poll/admin/recovery entries (F5)

This commit is contained in:
lda
2026-09-08 11:24:40 +07:00 Verified
parent 15bd472bdc
commit 993ed07fd3
7 changed files with 293 additions and 22 deletions
+8
View File
@@ -23,6 +23,7 @@ from wf_artifacts.runs.store import FileRunStore
from wf_scheduling.calendar import OneShotSource
from wf_scheduling.dispatch import RunDispatcher
from wf_scheduling.models import Schedule
from wf_scheduling.ownership import SchedulerOwnership
from wf_scheduling.poll import Scheduler
from wf_scheduling.prepare import (
InvocationPreparer,
@@ -66,6 +67,7 @@ def _scheduler(
capacity=4,
preparer=preparer,
dispatcher=ScriptedDispatcher(script),
ownership=SchedulerOwnership(tmp_path / "sched", owner="test").acquire(),
)
return sched, sched_store, run_store
@@ -80,6 +82,7 @@ def test_scheduler_requires_typed_collaborators() -> None:
"capacity",
"preparer",
"dispatcher",
"ownership",
}
@@ -137,6 +140,7 @@ def test_occurrence_bindings_resolve_into_admission(tmp_path: Path) -> None:
assert admission.resolved_input["which"] == "b"
assert admission.deployment_revision == 3
assert admission.schedule_revision == 1
sched.ownership.release()
def test_unknown_deployment_rejects_without_a_run(tmp_path: Path) -> None:
@@ -151,6 +155,7 @@ def test_unknown_deployment_rejects_without_a_run(tmp_path: Path) -> None:
page = store.list_occurrences("gone", limit=100)
kinds = [r["kind"] for r in cast(list[dict[str, Any]], page["occurrences"])]
assert kinds == ["preflight-rejected"]
sched.ownership.release()
def test_missing_required_input_rejects_without_a_run(tmp_path: Path) -> None:
@@ -167,6 +172,7 @@ def test_missing_required_input_rejects_without_a_run(tmp_path: Path) -> None:
capacity=4,
preparer=preparer,
dispatcher=ScriptedDispatcher({"*": "hang"}),
ownership=SchedulerOwnership(tmp_path / "sched", owner="test").acquire(),
)
intended = ts(2026, 9, 8, 12, 0)
sched_store.create_schedule(_sched_model("need"))
@@ -178,6 +184,7 @@ def test_missing_required_input_rejects_without_a_run(tmp_path: Path) -> None:
entry = cast(list[dict[str, Any]], page["occurrences"])[0]
assert entry["kind"] == "preflight-rejected"
assert "missing-input" in entry["reason"]
sched.ownership.release()
def test_conflicting_schedule_targets_reject_without_a_run(tmp_path: Path) -> None:
@@ -206,6 +213,7 @@ def test_conflicting_schedule_targets_reject_without_a_run(tmp_path: Path) -> No
entry = cast(list[dict[str, Any]], page["occurrences"])[0]
assert entry["kind"] == "preflight-rejected"
assert entry["reason"].startswith("invalid-input:")
sched.ownership.release()
def test_preparer_rejection_type_shape() -> None: