From 84a7616341457c6682dc5bbe2c25acaeb8c51159 Mon Sep 17 00:00:00 2001 From: Public Source Publisher Date: Mon, 12 Oct 2026 07:12:06 +0000 Subject: [PATCH] Publish curated Unraid-AppOps-Gateway source from 1c6a58589e215177617aa20bfa9d877c67874950 --- PUBLIC_SOURCE_EXPORT.md | 2 +- PUBLIC_SOURCE_MANIFEST.json | 6 +- .../tests/test_runner_admission_controller.py | 222 ++++++++++++++++++ 3 files changed, 226 insertions(+), 4 deletions(-) diff --git a/PUBLIC_SOURCE_EXPORT.md b/PUBLIC_SOURCE_EXPORT.md index 43f49e1..95d81ca 100644 --- a/PUBLIC_SOURCE_EXPORT.md +++ b/PUBLIC_SOURCE_EXPORT.md @@ -1,3 +1,3 @@ # Public source export -This source snapshot was generated from the private canonical repository at revision `945a919d1a3bbd2bb5bd21eb221fc9b58d795d80`. It contains no private Git history or operational evidence. Changes are published from the canonical repository. +This source snapshot was generated from the private canonical repository at revision `1c6a58589e215177617aa20bfa9d877c67874950`. It contains no private Git history or operational evidence. Changes are published from the canonical repository. diff --git a/PUBLIC_SOURCE_MANIFEST.json b/PUBLIC_SOURCE_MANIFEST.json index 98eb4f5..c9578b5 100644 --- a/PUBLIC_SOURCE_MANIFEST.json +++ b/PUBLIC_SOURCE_MANIFEST.json @@ -1,6 +1,6 @@ { "schemaVersion": 1, - "sourceRevision": "945a919d1a3bbd2bb5bd21eb221fc9b58d795d80", + "sourceRevision": "1c6a58589e215177617aa20bfa9d877c67874950", "files": [ { "path": ".dockerignore", @@ -1604,8 +1604,8 @@ }, { "path": "backend/tests/test_runner_admission_controller.py", - "sha256": "c05470d633c3f8c745522019724de85f470df926235fe7155f9aa754ea3e4e23", - "bytes": 69519 + "sha256": "05c4397dc9c155b6f5ba0721f1db6c231dfe3ef7a20bc0cc1a82569f47a6e655", + "bytes": 80570 }, { "path": "backend/tests/test_runner_admission_policy.py", diff --git a/backend/tests/test_runner_admission_controller.py b/backend/tests/test_runner_admission_controller.py index e95f627..a772623 100644 --- a/backend/tests/test_runner_admission_controller.py +++ b/backend/tests/test_runner_admission_controller.py @@ -55,6 +55,228 @@ def _host_gate_sample(module, monkeypatch): return controller, now, host, capacity +def test_durable_saves_preserve_pending_and_profile_references( + controller_module, monkeypatch, tmp_path +): + module = controller_module + tmp_path.chmod(0o700) + monkeypatch.setattr(module, "STATE_ROOT", tmp_path) + monkeypatch.setattr(module, "STATE_FILE", tmp_path / "admission.json") + controller = module.RunnerAdmissionController() + state = module._initial_state() + entry = state["profiles"]["frontend"] + pending = {"profileId": "frontend", "stage": "reserved"} + state["pending"] = pending + + controller._save_state(state) + pending["stage"] = "enable_requested" + controller._save_state(state) + entry["enabledByController"] = True + entry["observed"] = True + state["pending"] = None + controller._save_state(state) + + saved = controller._read_state() + assert saved["revision"] == state["revision"] == 3 + assert saved["profiles"]["frontend"]["enabledByController"] is True + assert saved["profiles"]["frontend"]["observed"] is True + assert saved["pending"] is None + + +def test_durable_save_preserves_drain_entry_updates( + controller_module, monkeypatch, tmp_path +): + module = controller_module + tmp_path.chmod(0o700) + monkeypatch.setattr(module, "STATE_ROOT", tmp_path) + monkeypatch.setattr(module, "STATE_FILE", tmp_path / "admission.json") + controller = module.RunnerAdmissionController() + state = module._initial_state() + entry = state["profiles"]["frontend"] + entry.update(enabledByController=True, drainOwned=True) + controller._save_state(state) + entry.update(enabledByController=False, drainOwned=False, idleSince=None) + controller._save_state(state) + + saved = controller._read_state() + assert saved["profiles"]["frontend"]["enabledByController"] is False + assert saved["profiles"]["frontend"]["drainOwned"] is False + + +def _operator_handover_fixture(module, monkeypatch): + controller, state, observation, _, _ = _lease_fixture(module, enabled=("frontend",)) + entry = state["profiles"]["frontend"] + entry.update(enabledByController=False, operatorEnabled=True) + state["bootstrapReceiptSha256"] = "a" * 64 + observation.update(specialization="active", resourceProof={"ready": True}, + taskImagesVerified=True, guardState="clear") + observation["containers"][module.RUNNER_PROFILES["frontend"].container_name].update( + pid=1234, startedAt=module._utc_iso()) + monkeypatch.setattr(module.os, "geteuid", lambda: 0, raising=False) + artifact = {"sourceRevision": "b" * 40, "artifactSha256": "c" * 64} + monkeypatch.setitem(sys.modules, "status_server", SimpleNamespace(_require_controller_release=lambda: artifact)) + monkeypatch.setattr(controller, "_process_lock", lambda: nullcontext()) + monkeypatch.setattr(controller, "_read_state", lambda: state) + monkeypatch.setattr(controller, "_observe", lambda: observation) + written = [] + + def persist(value, *, expected_revision): + assert value["revision"] == expected_revision + saved = json.loads(json.dumps(value)) + saved["revision"] += 1 + written.append(saved) + return saved + + monkeypatch.setattr(controller, "_write_state", persist) + monkeypatch.setattr(controller, "_set_disabled", lambda *_args: pytest.fail("handover must not patch Gitea")) + monkeypatch.setattr(controller, "_docker_run", lambda *_args, **_kw: pytest.fail("handover must not mutate Docker")) + return controller, state, observation, written, artifact + + +def test_explicit_operator_handover_is_bound_and_only_transfers_metadata(controller_module, monkeypatch): + controller, state, _, written, _ = _operator_handover_fixture(controller_module, monkeypatch) + preflight = controller.operator_lease_handover("frontend") + assert preflight["executed"] is False + assert written == [] + assert state["profiles"]["frontend"]["operatorEnabled"] is True + result = controller.operator_lease_handover("frontend", expected_preflight=preflight["preflightSha256"]) + assert result["status"] == "handed_over" and result["executed"] is True + assert len(written) == 1 + entry = written[0]["profiles"]["frontend"] + assert entry["operatorEnabled"] is False and entry["enabledByController"] is True + assert entry["lastOperatorHandover"]["containerId"] == preflight["containerId"] + assert all(written[0]["profiles"][p] == state["profiles"][p] for p in controller_module.PROFILE_IDS if p != "frontend") + with pytest.raises(controller_module.RunnerAdmissionError, match="preconditions_failed"): + controller.operator_lease_handover("frontend", expected_preflight=preflight["preflightSha256"]) + assert len(written) == 1 + + +@pytest.mark.parametrize("change", ["busy", "active", "disabled", "operator_disabled", "controller_owned", + "pending", "inactive", "bootstrap", "identity", "stopped", "pid", "started", "resource", "images", "guard"]) +def test_operator_handover_refuses_unsafe_or_unowned_observations(controller_module, monkeypatch, change): + controller, state, observation, written, _ = _operator_handover_fixture(controller_module, monkeypatch) + entry = state["profiles"]["frontend"] + row = observation["runnerRows"][controller_module.RUNNER_PROFILES["frontend"].container_name] + container = observation["containers"][controller_module.RUNNER_PROFILES["frontend"].container_name] + if change == "busy": + row["busy"] = True + elif change == "active": + observation["activeJobs"] = {999: [{"id": "foreign-job"}]} + elif change == "disabled": + row["disabled"] = True + elif change == "operator_disabled": + entry["operatorDisabled"] = True + elif change == "controller_owned": + entry["enabledByController"] = True + elif change == "pending": + state["pending"] = {"profileId": "build"} + elif change == "inactive": + observation["specialization"] = "legacy" + elif change == "bootstrap": + state["bootstrapReceiptSha256"] = None + elif change == "identity": + row["id"] += 1 + elif change == "stopped": + container["running"] = False + elif change == "pid": + container["pid"] = 0 + elif change == "started": + container["startedAt"] = None + elif change == "resource": + observation["resourceProof"] = None + elif change == "images": + observation["taskImagesVerified"] = False + else: + observation["guardState"] = "paused" + before = copy.deepcopy(state) + with pytest.raises(controller_module.RunnerAdmissionError, match="preconditions_failed"): + controller.operator_lease_handover("frontend") + assert state == before and written == [] + + +@pytest.mark.parametrize("change", ["state", "container", "artifact", "labels", "restart"]) +def test_operator_handover_rechecks_current_fingerprint(controller_module, monkeypatch, change): + controller, state, observation, written, artifact = _operator_handover_fixture(controller_module, monkeypatch) + preflight = controller.operator_lease_handover("frontend") + name = controller_module.RUNNER_PROFILES["frontend"].container_name + if change == "state": + state["revision"] += 1 + elif change == "container": + observation["containers"][name]["id"] = "f" * 64 + elif change == "artifact": + artifact["sourceRevision"] = "d" * 40 + elif change == "restart": + observation["containers"][name]["pid"] += 1 + else: + observation["runnerRows"][name]["labels"].add("self-hosted") + with pytest.raises(controller_module.RunnerAdmissionError, match="preflight_changed"): + controller.operator_lease_handover("frontend", expected_preflight=preflight["preflightSha256"]) + assert written == [] + + +def test_operator_handover_requires_root_before_reading_controller_or_credentials(controller_module, monkeypatch): + controller = controller_module.RunnerAdmissionController() + monkeypatch.setattr(controller_module.os, "geteuid", lambda: 10001, raising=False) + monkeypatch.setattr(controller, "_read_state", lambda: pytest.fail("non-root must not read private state")) + with pytest.raises(controller_module.RunnerAdmissionError, match="requires_root"): + controller.operator_lease_handover("frontend") + + +def test_operator_handover_cas_conflict_does_not_claim_publication(controller_module, monkeypatch): + controller, _, _, written, _ = _operator_handover_fixture(controller_module, monkeypatch) + preflight = controller.operator_lease_handover("frontend") + + def conflict(*_args, **_kwargs): + raise controller_module.RunnerAdmissionError("runner_admission_state_conflict") + + monkeypatch.setattr(controller, "_write_state", conflict) + with pytest.raises(controller_module.RunnerAdmissionError, match="state_conflict"): + controller.operator_lease_handover("frontend", expected_preflight=preflight["preflightSha256"]) + assert written == [] + + +def test_operator_handover_reports_uncertain_durable_write(controller_module, monkeypatch): + controller, _, _, _, _ = _operator_handover_fixture(controller_module, monkeypatch) + preflight = controller.operator_lease_handover("frontend") + + def uncertain(*_args, **_kwargs): + raise controller_module.RunnerAdmissionError("runner_admission_state_write_failed") + + monkeypatch.setattr(controller, "_write_state", uncertain) + with pytest.raises(controller_module.RunnerAdmissionError, match="handover_outcome_unknown"): + controller.operator_lease_handover("frontend", expected_preflight=preflight["preflightSha256"]) + + +@pytest.mark.parametrize("args", [["--operator-handover", "frontend"], + ["--preflight-operator-handover", "frontend", "--confirm", "RETURN_CI_RUNNER_TO_MANAGED_ADMISSION"]]) +def test_handover_cli_refuses_missing_or_inappropriate_mutation_arguments(controller_module, args): + with pytest.raises(SystemExit) as exc: + controller_module.main(args) + assert exc.value.code == 2 + + +@pytest.mark.parametrize("error", [RuntimeError("fake-secret-never-output"), "uncertain"]) +def test_handover_cli_redacts_errors_and_does_not_misreport_unknown_writes(controller_module, monkeypatch, capsys, error): + controller = controller_module.RunnerAdmissionController() + + def refused(*_args, **_kwargs): + if error == "uncertain": + raise controller_module.RunnerAdmissionError("runner_admission_handover_outcome_unknown") + raise error + + monkeypatch.setattr(controller, "operator_lease_handover", refused) + monkeypatch.setattr(controller_module, "RunnerAdmissionController", lambda: controller) + assert controller_module.main(["--preflight-operator-handover", "frontend"]) == 1 + raw = capsys.readouterr().out + assert "fake-secret-never-output" not in raw + result = json.loads(raw) + if error == "uncertain": + assert result["status"] == "outcome_unknown" and result["executed"] is None + assert result["noMutation"] is False + else: + assert result["status"] == "blocked" and result["executed"] is False + + def test_safe_live_metric_fluctuations_do_not_restart_stable_headroom(controller_module, monkeypatch): module = controller_module controller, now, host, _ = _host_gate_sample(module, monkeypatch)