refactor(platform): harden LAB evidence and telemetry
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from pathlib import Path, PurePosixPath
|
||||
from types import SimpleNamespace
|
||||
|
||||
from fastapi import APIRouter
|
||||
@@ -9,6 +9,7 @@ from fastapi.routing import APIRoute
|
||||
from pytest import MonkeyPatch
|
||||
|
||||
import k1link.web.advanced_laboratory_api as advanced_api
|
||||
from k1link.laboratory import LaboratoryEvidenceDefinition, LaboratoryEvidenceRegistry
|
||||
from k1link.web.advanced_laboratory_api import build_advanced_laboratory_router
|
||||
|
||||
|
||||
@@ -24,6 +25,26 @@ def _endpoint(router: APIRouter, path: str) -> object:
|
||||
raise AssertionError(f"GET {path} route is missing")
|
||||
|
||||
|
||||
def _evidence_registry(
|
||||
root: Path,
|
||||
*,
|
||||
work_id: str,
|
||||
result_id_prefix: str,
|
||||
schema_version: str,
|
||||
) -> LaboratoryEvidenceRegistry:
|
||||
return LaboratoryEvidenceRegistry(
|
||||
definitions=(
|
||||
LaboratoryEvidenceDefinition(
|
||||
work_id=work_id,
|
||||
runtime_relative_root=PurePosixPath(root.name),
|
||||
result_id_prefix=result_id_prefix,
|
||||
document_name="manifest.json",
|
||||
result_schema_version=schema_version,
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def test_advanced_catalogs_are_empty_when_not_configured() -> None:
|
||||
router = build_advanced_laboratory_router()
|
||||
|
||||
@@ -53,6 +74,26 @@ def test_advanced_index_is_empty_when_not_configured() -> None:
|
||||
}
|
||||
|
||||
|
||||
def test_registry_index_does_not_follow_a_runtime_symlink(tmp_path: Path) -> None:
|
||||
actual = tmp_path / "actual"
|
||||
actual.mkdir()
|
||||
linked = tmp_path / "linked"
|
||||
linked.symlink_to(actual, target_is_directory=True)
|
||||
registry = _evidence_registry(
|
||||
linked,
|
||||
work_id="linked-lab",
|
||||
result_id_prefix="linked-result",
|
||||
schema_version="missioncore.linked-result/v1",
|
||||
)
|
||||
router = build_advanced_laboratory_router(
|
||||
evidence_registry=registry,
|
||||
evidence_runtime_root_provider=lambda: tmp_path,
|
||||
)
|
||||
route = _endpoint(router, "/api/v1/laboratory/advanced-index")
|
||||
|
||||
assert route()["items"] == [] # type: ignore[index,operator]
|
||||
|
||||
|
||||
def test_advanced_index_publishes_l34b_shadow_identity(tmp_path: Path) -> None:
|
||||
root = tmp_path / "l34b"
|
||||
digest = "d" * 64
|
||||
@@ -82,7 +123,13 @@ def test_advanced_index_publishes_l34b_shadow_identity(tmp_path: Path) -> None:
|
||||
encoding="utf-8",
|
||||
)
|
||||
router = build_advanced_laboratory_router(
|
||||
l34b_root_provider=lambda: root,
|
||||
evidence_registry=_evidence_registry(
|
||||
root,
|
||||
work_id="l34b-nested-box-consolidation-shadow",
|
||||
result_id_prefix="l34b-nested-box-consolidation-shadow",
|
||||
schema_version="missioncore.l34b-nested-box-consolidation-shadow/v1",
|
||||
),
|
||||
evidence_runtime_root_provider=lambda: root.parent,
|
||||
)
|
||||
route = _endpoint(router, "/api/v1/laboratory/advanced-index")
|
||||
|
||||
@@ -123,7 +170,13 @@ def test_advanced_index_publishes_l34c_shadow_identity(tmp_path: Path) -> None:
|
||||
encoding="utf-8",
|
||||
)
|
||||
router = build_advanced_laboratory_router(
|
||||
l34c_root_provider=lambda: root,
|
||||
evidence_registry=_evidence_registry(
|
||||
root,
|
||||
work_id="l34c-tile-seam-stitch-shadow",
|
||||
result_id_prefix="l34c-tile-seam-stitch-shadow",
|
||||
schema_version="missioncore.l34c-tile-seam-stitch-shadow/v1",
|
||||
),
|
||||
evidence_runtime_root_provider=lambda: root.parent,
|
||||
)
|
||||
route = _endpoint(router, "/api/v1/laboratory/advanced-index")
|
||||
|
||||
@@ -166,7 +219,13 @@ def test_advanced_index_publishes_l34d_candidate_identity(tmp_path: Path) -> Non
|
||||
encoding="utf-8",
|
||||
)
|
||||
router = build_advanced_laboratory_router(
|
||||
l34d_root_provider=lambda: root,
|
||||
evidence_registry=_evidence_registry(
|
||||
root,
|
||||
work_id="l34d-cumulative-postprocessing-candidate",
|
||||
result_id_prefix="l34d-cumulative-postprocessing-candidate",
|
||||
schema_version="missioncore.l34d-cumulative-postprocessing-candidate/v1",
|
||||
),
|
||||
evidence_runtime_root_provider=lambda: root.parent,
|
||||
)
|
||||
route = _endpoint(router, "/api/v1/laboratory/advanced-index")
|
||||
|
||||
@@ -207,7 +266,13 @@ def test_advanced_index_publishes_l34e_diagnostic_identity(tmp_path: Path) -> No
|
||||
encoding="utf-8",
|
||||
)
|
||||
router = build_advanced_laboratory_router(
|
||||
l34e_root_provider=lambda: root,
|
||||
evidence_registry=_evidence_registry(
|
||||
root,
|
||||
work_id="l34e-self-review-diagnostic",
|
||||
result_id_prefix="l34e-self-review-diagnostic",
|
||||
schema_version="missioncore.l34e-self-review-diagnostic/v1",
|
||||
),
|
||||
evidence_runtime_root_provider=lambda: root.parent,
|
||||
)
|
||||
route = _endpoint(router, "/api/v1/laboratory/advanced-index")
|
||||
|
||||
@@ -250,7 +315,13 @@ def test_advanced_index_publishes_l34f_adjudicated_reference_identity(
|
||||
encoding="utf-8",
|
||||
)
|
||||
router = build_advanced_laboratory_router(
|
||||
l34f_root_provider=lambda: root,
|
||||
evidence_registry=_evidence_registry(
|
||||
root,
|
||||
work_id="l34f-adjudicated-reference",
|
||||
result_id_prefix="l34f-adjudicated-reference",
|
||||
schema_version="missioncore.l34f-adjudicated-reference/v1",
|
||||
),
|
||||
evidence_runtime_root_provider=lambda: root.parent,
|
||||
)
|
||||
route = _endpoint(router, "/api/v1/laboratory/advanced-index")
|
||||
|
||||
|
||||
@@ -111,6 +111,7 @@ def test_worker_apply_uses_private_resolved_endpoint_and_confirms_service(
|
||||
"mqtt_port": 1883,
|
||||
"resolved_addresses": ["192.168.68.56"],
|
||||
"broker_reachable": True,
|
||||
"recovery_configured": True,
|
||||
}
|
||||
|
||||
monkeypatch.setattr(network, "_run_worker_powershell", run)
|
||||
@@ -121,6 +122,8 @@ def test_worker_apply_uses_private_resolved_endpoint_and_confirms_service(
|
||||
assert result["ready"] is True
|
||||
assert "__PAYLOAD_BASE64__" not in captured["script"]
|
||||
assert "MISSIONCORE_MQTT_PASSWORD" not in captured["script"]
|
||||
assert "restart/5000/restart/30000/restart/60000" in captured["script"]
|
||||
assert "failureflag telegraf 1" in captured["script"]
|
||||
assert captured["timeout"] == 35
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import hashlib
|
||||
import json
|
||||
import struct
|
||||
import zlib
|
||||
from pathlib import Path
|
||||
from pathlib import Path, PurePosixPath
|
||||
|
||||
import pytest
|
||||
from fastapi import APIRouter, HTTPException
|
||||
@@ -22,6 +22,7 @@ from k1link.compute.l34_right_yolox_truth_island_freeze import (
|
||||
L34_PREDICTIONS_NAME,
|
||||
L34_REPORT_NAME,
|
||||
)
|
||||
from k1link.laboratory import LaboratoryEvidenceDefinition, LaboratoryEvidenceRegistry
|
||||
from k1link.web.advanced_laboratory_api import build_advanced_laboratory_router
|
||||
from k1link.web.l34_annotation_api import (
|
||||
L34AnnotationCreateRequest,
|
||||
@@ -579,7 +580,20 @@ def test_l34_annotation_sessions_are_revisioned_and_not_truth(
|
||||
def test_advanced_index_includes_l34_by_real_creation_time(tmp_path: Path) -> None:
|
||||
result = _write_result(tmp_path)
|
||||
router = build_advanced_laboratory_router(
|
||||
l34_root_provider=lambda: tmp_path,
|
||||
evidence_registry=LaboratoryEvidenceRegistry(
|
||||
definitions=(
|
||||
LaboratoryEvidenceDefinition(
|
||||
work_id="l34-right-yolox-truth-island-freeze",
|
||||
runtime_relative_root=PurePosixPath(tmp_path.name),
|
||||
result_id_prefix="l34-right-yolox-truth-island-freeze",
|
||||
document_name="manifest.json",
|
||||
result_schema_version=(
|
||||
"missioncore.l34-right-yolox-truth-island-freeze/v1"
|
||||
),
|
||||
),
|
||||
)
|
||||
),
|
||||
evidence_runtime_root_provider=lambda: tmp_path.parent,
|
||||
)
|
||||
index = _endpoint(router, "/api/v1/laboratory/advanced-index")()
|
||||
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path, PurePosixPath
|
||||
|
||||
import pytest
|
||||
|
||||
from k1link.laboratory import (
|
||||
LaboratoryEvidenceDefinition,
|
||||
LaboratoryEvidenceRegistry,
|
||||
LaboratoryRegistryError,
|
||||
)
|
||||
|
||||
|
||||
def _definition(
|
||||
work_id: str,
|
||||
*,
|
||||
root: str | None = None,
|
||||
prefix: str | None = None,
|
||||
extra: dict[str, object] | None = None,
|
||||
) -> dict[str, object]:
|
||||
document: dict[str, object] = {
|
||||
"schema_version": "missioncore.laboratory-evidence-definition/v1",
|
||||
"work_id": work_id,
|
||||
"evidence": {
|
||||
"runtime_relative_root": root or f"{work_id}/results",
|
||||
"result_id_prefix": prefix or work_id,
|
||||
"document_name": "manifest.json",
|
||||
"schema_version": f"missioncore.{work_id}/v1",
|
||||
},
|
||||
}
|
||||
if extra is not None:
|
||||
document.update(extra)
|
||||
return document
|
||||
|
||||
|
||||
def _write(root: Path, work_id: str, document: dict[str, object]) -> Path:
|
||||
path = root / f"{work_id}.json"
|
||||
path.write_text(json.dumps(document), encoding="utf-8")
|
||||
return path
|
||||
|
||||
|
||||
def test_registry_loads_sorted_definitions_and_resolves_beneath_runtime_root(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
definitions = tmp_path / "definitions"
|
||||
definitions.mkdir()
|
||||
_write(definitions, "z-last", _definition("z-last"))
|
||||
_write(
|
||||
definitions,
|
||||
"a-first",
|
||||
_definition("a-first", root="family/a-first/results"),
|
||||
)
|
||||
|
||||
registry = LaboratoryEvidenceRegistry.from_directory(definitions)
|
||||
|
||||
assert [item.work_id for item in registry.definitions] == ["a-first", "z-last"]
|
||||
first = registry.definitions[0]
|
||||
assert first.result_root(tmp_path / "runtime") == (
|
||||
tmp_path / "runtime" / "family" / "a-first" / "results"
|
||||
)
|
||||
assert first.result_id_pattern.fullmatch(f"a-first-{'a' * 64}") is not None
|
||||
assert first.result_id_pattern.fullmatch("a-first-not-a-digest") is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize("unsafe_root", ["../escape", "/absolute", "a\\b", "."])
|
||||
def test_registry_rejects_unsafe_runtime_roots(
|
||||
tmp_path: Path,
|
||||
unsafe_root: str,
|
||||
) -> None:
|
||||
definitions = tmp_path / "definitions"
|
||||
definitions.mkdir()
|
||||
_write(definitions, "unsafe-lab", _definition("unsafe-lab", root=unsafe_root))
|
||||
|
||||
with pytest.raises(LaboratoryRegistryError, match="runtime_relative_root"):
|
||||
LaboratoryEvidenceRegistry.from_directory(definitions)
|
||||
|
||||
|
||||
def test_registry_rejects_unknown_keys(tmp_path: Path) -> None:
|
||||
definitions = tmp_path / "definitions"
|
||||
definitions.mkdir()
|
||||
_write(
|
||||
definitions,
|
||||
"strict-lab",
|
||||
_definition("strict-lab", extra={"renderer": "hard-coded"}),
|
||||
)
|
||||
|
||||
with pytest.raises(LaboratoryRegistryError, match=r"unexpected=\['renderer'\]"):
|
||||
LaboratoryEvidenceRegistry.from_directory(definitions)
|
||||
|
||||
|
||||
def test_registry_rejects_symlinked_definitions(tmp_path: Path) -> None:
|
||||
definitions = tmp_path / "definitions"
|
||||
definitions.mkdir()
|
||||
outside = tmp_path / "outside.json"
|
||||
outside.write_text(json.dumps(_definition("linked-lab")), encoding="utf-8")
|
||||
(definitions / "linked-lab.json").symlink_to(outside)
|
||||
|
||||
with pytest.raises(LaboratoryRegistryError, match="regular file"):
|
||||
LaboratoryEvidenceRegistry.from_directory(definitions)
|
||||
|
||||
|
||||
def test_registry_rejects_ambiguous_result_prefixes(tmp_path: Path) -> None:
|
||||
definitions = tmp_path / "definitions"
|
||||
definitions.mkdir()
|
||||
_write(definitions, "first-lab", _definition("first-lab", prefix="shared-result"))
|
||||
_write(definitions, "second-lab", _definition("second-lab", prefix="shared-result"))
|
||||
|
||||
with pytest.raises(LaboratoryRegistryError, match="duplicate LAB result_id_prefix"):
|
||||
LaboratoryEvidenceRegistry.from_directory(definitions)
|
||||
|
||||
|
||||
def test_definition_constructor_cannot_bypass_path_validation() -> None:
|
||||
with pytest.raises(LaboratoryRegistryError, match="runtime_relative_root"):
|
||||
LaboratoryEvidenceDefinition(
|
||||
work_id="unsafe-lab",
|
||||
runtime_relative_root=PurePosixPath("../escape"),
|
||||
result_id_prefix="unsafe-result",
|
||||
document_name="manifest.json",
|
||||
result_schema_version="missioncore.unsafe-result/v1",
|
||||
)
|
||||
|
||||
|
||||
def test_product_registry_declares_every_advanced_evidence_source() -> None:
|
||||
repository_root = Path(__file__).resolve().parents[1]
|
||||
registry = LaboratoryEvidenceRegistry.from_directory(
|
||||
repository_root / "config" / "laboratories"
|
||||
)
|
||||
|
||||
assert len(registry.definitions) == 27
|
||||
assert {item.work_id for item in registry.definitions} >= {
|
||||
"e31-source-binding",
|
||||
"e46j-raw-fisheye-realtime",
|
||||
"l34f-adjudicated-reference",
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
REPOSITORY_ROOT = Path(__file__).resolve().parents[1]
|
||||
TELEGRAF_ROOT = REPOSITORY_ROOT / "deploy" / "telemetry-plane" / "telegraf"
|
||||
RECOVERY_ACTIONS = "restart/5000/restart/30000/restart/60000"
|
||||
|
||||
|
||||
def test_install_configures_bounded_service_recovery() -> None:
|
||||
script = (TELEGRAF_ROOT / "Install-NdcMissionCoreTelegraf.ps1").read_text(encoding="utf-8")
|
||||
|
||||
assert "sc.exe failure $serviceName reset= 86400" in script
|
||||
assert RECOVERY_ACTIONS in script
|
||||
assert "sc.exe failureflag $serviceName 1" in script
|
||||
assert "RecoveryConfigured = $true" in script
|
||||
|
||||
|
||||
def test_update_configures_recovery_inside_rollback_boundary() -> None:
|
||||
script = (TELEGRAF_ROOT / "Update-NdcMissionCoreTelegraf.ps1").read_text(encoding="utf-8")
|
||||
|
||||
recovery = script.index("sc.exe failure $serviceName reset= 86400")
|
||||
rollback = script.index("Stop-Service -Name $serviceName -Force", recovery)
|
||||
restore_environment = script.index(
|
||||
"-Type MultiString -Value $serviceEnvironmentBefore",
|
||||
rollback,
|
||||
)
|
||||
restart = script.index("Start-Service -Name $serviceName", restore_environment)
|
||||
assert recovery < rollback < restore_environment < restart
|
||||
assert RECOVERY_ACTIONS in script
|
||||
assert "sc.exe failureflag $serviceName 1" in script
|
||||
assert "RecoveryConfigured = $true" in script
|
||||
Reference in New Issue
Block a user