refactor(worker): externalize runtime registries
This commit is contained in:
@@ -12,11 +12,12 @@ ENV PYTHONPATH=/opt/nodedc/mission-core/src \
|
|||||||
WORKDIR /opt/nodedc/mission-core
|
WORKDIR /opt/nodedc/mission-core
|
||||||
|
|
||||||
COPY src/k1link ./src/k1link
|
COPY src/k1link ./src/k1link
|
||||||
COPY config ./config
|
|
||||||
COPY experiments/perception/worker/observatory_portable/worker-006-agent-build-context.json \
|
COPY experiments/perception/worker/observatory_portable/worker-006-agent-build-context.json \
|
||||||
./release/worker-006-agent-build-context.json
|
./release/worker-006-agent-build-context.json
|
||||||
|
|
||||||
RUN case "${NODEDC_SOURCE_REVISION}" in \
|
RUN mkdir -p /run/nodedc/registries \
|
||||||
|
&& chmod 0555 /run/nodedc /run/nodedc/registries \
|
||||||
|
&& case "${NODEDC_SOURCE_REVISION}" in \
|
||||||
*[!0-9a-f]* ) exit 64 ;; \
|
*[!0-9a-f]* ) exit 64 ;; \
|
||||||
* ) ;; \
|
* ) ;; \
|
||||||
esac \
|
esac \
|
||||||
@@ -45,6 +46,7 @@ LABEL org.opencontainers.image.title="NODE.DC Observatory Worker 006 agent" \
|
|||||||
com.nodedc.worker-contour="worker-006" \
|
com.nodedc.worker-contour="worker-006" \
|
||||||
com.nodedc.authority="observation-only" \
|
com.nodedc.authority="observation-only" \
|
||||||
com.nodedc.models="external" \
|
com.nodedc.models="external" \
|
||||||
|
com.nodedc.runtime-registries="external-read-only" \
|
||||||
com.nodedc.base-image.sha256="58df7489c3f2276f9591d500a012dee03e23d35543ce3c390b4c001e6bf90794" \
|
com.nodedc.base-image.sha256="58df7489c3f2276f9591d500a012dee03e23d35543ce3c390b4c001e6bf90794" \
|
||||||
com.nodedc.build-context.sha256="${NODEDC_BUILD_CONTEXT_SHA256}"
|
com.nodedc.build-context.sha256="${NODEDC_BUILD_CONTEXT_SHA256}"
|
||||||
|
|
||||||
|
|||||||
+22
-10
@@ -27,11 +27,6 @@
|
|||||||
"kind": "tree",
|
"kind": "tree",
|
||||||
"image_path": "/opt/nodedc/mission-core/src/k1link"
|
"image_path": "/opt/nodedc/mission-core/src/k1link"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"path": "config",
|
|
||||||
"kind": "tree",
|
|
||||||
"image_path": "/opt/nodedc/mission-core/config"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"path": "experiments/perception/worker/observatory_portable/Dockerfile.worker-006-agent",
|
"path": "experiments/perception/worker/observatory_portable/Dockerfile.worker-006-agent",
|
||||||
"kind": "file",
|
"kind": "file",
|
||||||
@@ -43,11 +38,24 @@
|
|||||||
"image_path": "/opt/nodedc/mission-core/release/worker-006-agent-build-context.json"
|
"image_path": "/opt/nodedc/mission-core/release/worker-006-agent-build-context.json"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"required_configuration": [
|
"embedded_configuration": [],
|
||||||
"config/observatory-portable-run-definitions.json",
|
"external_runtime_files": [
|
||||||
"config/observatory-worker-runtime-candidates.json",
|
{
|
||||||
"config/perception/m49-tgs-portable-v2.json",
|
"role": "portable-run-definition-registry",
|
||||||
"config/perception/lab-v1-eomt-ddrnet-portable-v2.json"
|
"environment_variable": "MISSIONCORE_OBSERVATORY_WORKER_DEFINITIONS_FILE",
|
||||||
|
"container_path": "/run/nodedc/registries/observatory-portable-run-definitions.json",
|
||||||
|
"binding": "exact-read-only-regular-file",
|
||||||
|
"identity_owner": "post-image runtime installation",
|
||||||
|
"baked_into_image": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "portable-worker-runtime-registry",
|
||||||
|
"environment_variable": "MISSIONCORE_OBSERVATORY_WORKER_RUNTIME_REGISTRY_FILE",
|
||||||
|
"container_path": "/run/nodedc/registries/observatory-worker-runtime-candidates.json",
|
||||||
|
"binding": "exact-read-only-regular-file",
|
||||||
|
"identity_owner": "post-image runtime installation",
|
||||||
|
"baked_into_image": false
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"runtime": {
|
"runtime": {
|
||||||
"pythonpath": "/opt/nodedc/mission-core/src",
|
"pythonpath": "/opt/nodedc/mission-core/src",
|
||||||
@@ -57,11 +65,15 @@
|
|||||||
"k1link.observatory.m49_worker_container_main"
|
"k1link.observatory.m49_worker_container_main"
|
||||||
],
|
],
|
||||||
"composition_module": "k1link.observatory.m49_worker_service",
|
"composition_module": "k1link.observatory.m49_worker_service",
|
||||||
|
"configuration_baked_into_image": false,
|
||||||
|
"runtime_registries_baked_into_image": false,
|
||||||
"models_baked_into_image": false,
|
"models_baked_into_image": false,
|
||||||
"executor_releases_baked_into_image": false
|
"executor_releases_baked_into_image": false
|
||||||
},
|
},
|
||||||
"forbidden_context": [
|
"forbidden_context": [
|
||||||
"model weights",
|
"model weights",
|
||||||
|
"run-definition registries",
|
||||||
|
"runtime-candidate registries",
|
||||||
"recorded K1 sessions",
|
"recorded K1 sessions",
|
||||||
"worker bearer credentials",
|
"worker bearer credentials",
|
||||||
"executor release payloads",
|
"executor release payloads",
|
||||||
|
|||||||
+60
-10
@@ -55,6 +55,7 @@
|
|||||||
"com.nodedc.worker-contour": "worker-006",
|
"com.nodedc.worker-contour": "worker-006",
|
||||||
"com.nodedc.authority": "observation-only",
|
"com.nodedc.authority": "observation-only",
|
||||||
"com.nodedc.models": "external",
|
"com.nodedc.models": "external",
|
||||||
|
"com.nodedc.runtime-registries": "external-read-only",
|
||||||
"com.nodedc.base-image.sha256": "58df7489c3f2276f9591d500a012dee03e23d35543ce3c390b4c001e6bf90794",
|
"com.nodedc.base-image.sha256": "58df7489c3f2276f9591d500a012dee03e23d35543ce3c390b4c001e6bf90794",
|
||||||
"com.nodedc.build-context.sha256": "<build-context-sha256>"
|
"com.nodedc.build-context.sha256": "<build-context-sha256>"
|
||||||
},
|
},
|
||||||
@@ -76,9 +77,41 @@
|
|||||||
"MISSIONCORE_OBSERVATORY_WORKER_BASE_URL": "http://127.0.0.1:18080",
|
"MISSIONCORE_OBSERVATORY_WORKER_BASE_URL": "http://127.0.0.1:18080",
|
||||||
"MISSIONCORE_OBSERVATORY_WORKER_TOKEN_FILE": "/run/secrets/observatory-worker.token",
|
"MISSIONCORE_OBSERVATORY_WORKER_TOKEN_FILE": "/run/secrets/observatory-worker.token",
|
||||||
"MISSIONCORE_OBSERVATORY_WORKER_WORK_ROOT": "/work",
|
"MISSIONCORE_OBSERVATORY_WORKER_WORK_ROOT": "/work",
|
||||||
"MISSIONCORE_OBSERVATORY_WORKER_DEFINITIONS_FILE": "/opt/nodedc/mission-core/config/observatory-portable-run-definitions.json",
|
"MISSIONCORE_OBSERVATORY_WORKER_DEFINITIONS_FILE": "/run/nodedc/registries/observatory-portable-run-definitions.json",
|
||||||
"MISSIONCORE_OBSERVATORY_WORKER_RUNTIME_REGISTRY_FILE": "/opt/nodedc/mission-core/config/observatory-worker-runtime-candidates.json",
|
"MISSIONCORE_OBSERVATORY_WORKER_RUNTIME_REGISTRY_FILE": "/run/nodedc/registries/observatory-worker-runtime-candidates.json",
|
||||||
"MISSIONCORE_OBSERVATORY_M49_INSTALLATION_RECEIPT_FILE": "/release/worker-installation-receipt.json"
|
"MISSIONCORE_OBSERVATORY_M49_INSTALLATION_RECEIPT_FILE": "/release/worker-installation-receipt.json",
|
||||||
|
"MISSIONCORE_OBSERVATORY_LAB_V1_INSTALLATION_RECEIPT_FILE": "/release/lab-v1-worker-installation-receipt.json"
|
||||||
|
},
|
||||||
|
"runtime_registry_files": {
|
||||||
|
"binding": "individual read-only bind files",
|
||||||
|
"identity_timing": "filled and verified after coordinator image build",
|
||||||
|
"included_in_coordinator_image_or_image_receipt": false,
|
||||||
|
"required": [
|
||||||
|
{
|
||||||
|
"role": "portable-run-definition-registry",
|
||||||
|
"environment_variable": "MISSIONCORE_OBSERVATORY_WORKER_DEFINITIONS_FILE",
|
||||||
|
"host_path": null,
|
||||||
|
"container_path": "/run/nodedc/registries/observatory-portable-run-definitions.json",
|
||||||
|
"byte_length": null,
|
||||||
|
"sha256": null,
|
||||||
|
"mode": "read-only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "portable-worker-runtime-registry",
|
||||||
|
"environment_variable": "MISSIONCORE_OBSERVATORY_WORKER_RUNTIME_REGISTRY_FILE",
|
||||||
|
"host_path": null,
|
||||||
|
"container_path": "/run/nodedc/registries/observatory-worker-runtime-candidates.json",
|
||||||
|
"byte_length": null,
|
||||||
|
"sha256": null,
|
||||||
|
"mode": "read-only"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"required_preflight": [
|
||||||
|
"fill one exact absolute host path, byte length and SHA-256 for each registry after the coordinator image identity exists",
|
||||||
|
"reject missing, symbolic-link, non-regular or identity-mismatched registry files before container start",
|
||||||
|
"bind each registry as its own read-only file at the fixed container path",
|
||||||
|
"reject any registry path inside the coordinator image"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"uid": 0,
|
"uid": 0,
|
||||||
@@ -121,9 +154,13 @@
|
|||||||
"force-delete exact created container ID"
|
"force-delete exact created container ID"
|
||||||
],
|
],
|
||||||
"sibling_runtime_fences": {
|
"sibling_runtime_fences": {
|
||||||
"exact_image_sha256s": {
|
"component_image_identity": {
|
||||||
"eomt": "58df7489c3f2276f9591d500a012dee03e23d35543ce3c390b4c001e6bf90794",
|
"source": "/release/lab-v1-worker-installation-receipt.json",
|
||||||
"ddrnet": "591cb382c099eeb05e7ec16e2371e0b2da54d2bb5c49ec0f4ac88dbf72b0f0cd"
|
"schema_version": "missioncore.observatory-portable-lab-v1-worker-installation-ready-receipt/v1",
|
||||||
|
"fields": "component_installations.<eomt-or-ddrnet>.image_sha256",
|
||||||
|
"image_kind": "derived adapter image",
|
||||||
|
"base_image_ids_are_component_ids": false,
|
||||||
|
"queued_job_override_allowed": false
|
||||||
},
|
},
|
||||||
"commands_and_entrypoints": "exact values sealed in the LAB V1 runner installation receipt; never supplied by a queued job",
|
"commands_and_entrypoints": "exact values sealed in the LAB V1 runner installation receipt; never supplied by a queued job",
|
||||||
"bind_sources": "only exact Worker-host asset roots sealed in the LAB V1 runner installation receipt and descendants of its exact work-root binding",
|
"bind_sources": "only exact Worker-host asset roots sealed in the LAB V1 runner installation receipt and descendants of its exact work-root binding",
|
||||||
@@ -179,6 +216,16 @@
|
|||||||
"container_path": "/run/secrets",
|
"container_path": "/run/secrets",
|
||||||
"mode": "read-only",
|
"mode": "read-only",
|
||||||
"purpose": "private bearer token file"
|
"purpose": "private bearer token file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"container_path": "/run/nodedc/registries/observatory-portable-run-definitions.json",
|
||||||
|
"mode": "read-only",
|
||||||
|
"purpose": "exact external portable RunDefinition registry file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"container_path": "/run/nodedc/registries/observatory-worker-runtime-candidates.json",
|
||||||
|
"mode": "read-only",
|
||||||
|
"purpose": "exact external portable runtime candidate registry file"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"external_assets": {
|
"external_assets": {
|
||||||
@@ -188,10 +235,12 @@
|
|||||||
"queued_jobs_may_select_paths_or_commands": false
|
"queued_jobs_may_select_paths_or_commands": false
|
||||||
},
|
},
|
||||||
"lab_v1_runner_installation_input": {
|
"lab_v1_runner_installation_input": {
|
||||||
"state": "loader-contract-not-yet-defined",
|
"state": "external-installed-receipt-required",
|
||||||
"environment_variable": null,
|
"environment_variable": "MISSIONCORE_OBSERVATORY_LAB_V1_INSTALLATION_RECEIPT_FILE",
|
||||||
"container_path": null,
|
"container_path": "/release/lab-v1-worker-installation-receipt.json",
|
||||||
"reason": "the current local runner module defines an in-memory sealed installation receipt but no environment loader or installed receipt path"
|
"mode": "read-only",
|
||||||
|
"owns_component_image_identities": true,
|
||||||
|
"queued_jobs_may_override_component_images": false
|
||||||
},
|
},
|
||||||
"protected_contours": [
|
"protected_contours": [
|
||||||
"K1 connection and control",
|
"K1 connection and control",
|
||||||
@@ -217,6 +266,7 @@
|
|||||||
"result": "not-run"
|
"result": "not-run"
|
||||||
},
|
},
|
||||||
"models_baked_into_image": false,
|
"models_baked_into_image": false,
|
||||||
|
"runtime_registries_baked_into_image": false,
|
||||||
"authority": {
|
"authority": {
|
||||||
"commands_enabled": false,
|
"commands_enabled": false,
|
||||||
"actuation_allowed": false,
|
"actuation_allowed": false,
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ import re
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import cast
|
from typing import cast
|
||||||
|
|
||||||
from k1link.observatory import portable_lab_v1_local_runners as local_runners
|
|
||||||
|
|
||||||
REPOSITORY_ROOT = Path(__file__).resolve().parents[1]
|
REPOSITORY_ROOT = Path(__file__).resolve().parents[1]
|
||||||
ARTIFACT_ROOT = (
|
ARTIFACT_ROOT = (
|
||||||
REPOSITORY_ROOT / "experiments" / "perception" / "worker" / "observatory_portable"
|
REPOSITORY_ROOT / "experiments" / "perception" / "worker" / "observatory_portable"
|
||||||
@@ -23,6 +21,14 @@ AUTHORITY = {
|
|||||||
"navigation_or_safety_accepted": False,
|
"navigation_or_safety_accepted": False,
|
||||||
"production_accepted": False,
|
"production_accepted": False,
|
||||||
}
|
}
|
||||||
|
DOCKER_SOCKET = "/var/run/docker.sock"
|
||||||
|
DEFINITIONS_CONTAINER_PATH = (
|
||||||
|
"/run/nodedc/registries/observatory-portable-run-definitions.json"
|
||||||
|
)
|
||||||
|
RUNTIME_REGISTRY_CONTAINER_PATH = (
|
||||||
|
"/run/nodedc/registries/observatory-worker-runtime-candidates.json"
|
||||||
|
)
|
||||||
|
LAB_V1_RECEIPT_CONTAINER_PATH = "/release/lab-v1-worker-installation-receipt.json"
|
||||||
|
|
||||||
|
|
||||||
def _document(path: Path) -> dict[str, object]:
|
def _document(path: Path) -> dict[str, object]:
|
||||||
@@ -45,8 +51,11 @@ def test_agent_dockerfile_is_offline_commit_bound_and_model_free() -> None:
|
|||||||
assert 'ENTRYPOINT ["python3", "-m", "k1link.observatory.m49_worker_container_main"]' in payload
|
assert 'ENTRYPOINT ["python3", "-m", "k1link.observatory.m49_worker_container_main"]' in payload
|
||||||
assert "CMD []" in payload
|
assert "CMD []" in payload
|
||||||
assert "COPY src/k1link ./src/k1link" in payload
|
assert "COPY src/k1link ./src/k1link" in payload
|
||||||
assert "COPY config ./config" in payload
|
assert "COPY config" not in payload
|
||||||
assert "COPY . ." not in payload
|
assert "COPY . ." not in payload
|
||||||
|
assert "mkdir -p /run/nodedc/registries" in payload
|
||||||
|
assert "chmod 0555 /run/nodedc /run/nodedc/registries" in payload
|
||||||
|
assert 'com.nodedc.runtime-registries="external-read-only"' in payload
|
||||||
assert re.search(r"(?im)^\s*(?:run\s+)?(?:apt|apk|yum|dnf|pip|uv)\b", payload) is None
|
assert re.search(r"(?im)^\s*(?:run\s+)?(?:apt|apk|yum|dnf|pip|uv)\b", payload) is None
|
||||||
assert "curl " not in payload.lower()
|
assert "curl " not in payload.lower()
|
||||||
assert "wget " not in payload.lower()
|
assert "wget " not in payload.lower()
|
||||||
@@ -85,7 +94,6 @@ def test_build_context_is_only_repo_source_configuration_and_artifact_contract()
|
|||||||
paths = [cast(str, row["path"]) for row in entries]
|
paths = [cast(str, row["path"]) for row in entries]
|
||||||
assert paths == [
|
assert paths == [
|
||||||
"src/k1link",
|
"src/k1link",
|
||||||
"config",
|
|
||||||
"experiments/perception/worker/observatory_portable/Dockerfile.worker-006-agent",
|
"experiments/perception/worker/observatory_portable/Dockerfile.worker-006-agent",
|
||||||
"experiments/perception/worker/observatory_portable/worker-006-agent-build-context.json",
|
"experiments/perception/worker/observatory_portable/worker-006-agent-build-context.json",
|
||||||
]
|
]
|
||||||
@@ -97,19 +105,41 @@ def test_build_context_is_only_repo_source_configuration_and_artifact_contract()
|
|||||||
for token in ("model", "weight", "session", "credential", "runtime")
|
for token in ("model", "weight", "session", "credential", "runtime")
|
||||||
)
|
)
|
||||||
|
|
||||||
required = cast(list[str], document["required_configuration"])
|
assert document["embedded_configuration"] == []
|
||||||
assert required == [
|
assert "required_configuration" not in document
|
||||||
"config/observatory-portable-run-definitions.json",
|
external_runtime_files = cast(
|
||||||
"config/observatory-worker-runtime-candidates.json",
|
list[dict[str, object]], document["external_runtime_files"]
|
||||||
"config/perception/m49-tgs-portable-v2.json",
|
)
|
||||||
"config/perception/lab-v1-eomt-ddrnet-portable-v2.json",
|
assert external_runtime_files == [
|
||||||
|
{
|
||||||
|
"role": "portable-run-definition-registry",
|
||||||
|
"environment_variable": "MISSIONCORE_OBSERVATORY_WORKER_DEFINITIONS_FILE",
|
||||||
|
"container_path": DEFINITIONS_CONTAINER_PATH,
|
||||||
|
"binding": "exact-read-only-regular-file",
|
||||||
|
"identity_owner": "post-image runtime installation",
|
||||||
|
"baked_into_image": False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "portable-worker-runtime-registry",
|
||||||
|
"environment_variable": (
|
||||||
|
"MISSIONCORE_OBSERVATORY_WORKER_RUNTIME_REGISTRY_FILE"
|
||||||
|
),
|
||||||
|
"container_path": RUNTIME_REGISTRY_CONTAINER_PATH,
|
||||||
|
"binding": "exact-read-only-regular-file",
|
||||||
|
"identity_owner": "post-image runtime installation",
|
||||||
|
"baked_into_image": False,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
assert all((REPOSITORY_ROOT / relative).is_file() for relative in required)
|
|
||||||
runtime = cast(dict[str, object], document["runtime"])
|
runtime = cast(dict[str, object], document["runtime"])
|
||||||
assert runtime["entrypoint"] == ENTRYPOINT
|
assert runtime["entrypoint"] == ENTRYPOINT
|
||||||
assert runtime["composition_module"] == "k1link.observatory.m49_worker_service"
|
assert runtime["composition_module"] == "k1link.observatory.m49_worker_service"
|
||||||
|
assert runtime["configuration_baked_into_image"] is False
|
||||||
|
assert runtime["runtime_registries_baked_into_image"] is False
|
||||||
assert runtime["models_baked_into_image"] is False
|
assert runtime["models_baked_into_image"] is False
|
||||||
assert runtime["executor_releases_baked_into_image"] is False
|
assert runtime["executor_releases_baked_into_image"] is False
|
||||||
|
forbidden = cast(list[str], document["forbidden_context"])
|
||||||
|
assert "run-definition registries" in forbidden
|
||||||
|
assert "runtime-candidate registries" in forbidden
|
||||||
|
|
||||||
|
|
||||||
def test_install_plan_requires_offline_build_hardening_smoke_and_unfilled_receipt() -> None:
|
def test_install_plan_requires_offline_build_hardening_smoke_and_unfilled_receipt() -> None:
|
||||||
@@ -162,6 +192,7 @@ def test_install_plan_requires_offline_build_hardening_smoke_and_unfilled_receip
|
|||||||
assert labels["org.opencontainers.image.revision"] == "<source-revision>"
|
assert labels["org.opencontainers.image.revision"] == "<source-revision>"
|
||||||
assert labels["com.nodedc.base-image.sha256"] == BASE_SHA256
|
assert labels["com.nodedc.base-image.sha256"] == BASE_SHA256
|
||||||
assert labels["com.nodedc.models"] == "external"
|
assert labels["com.nodedc.models"] == "external"
|
||||||
|
assert labels["com.nodedc.runtime-registries"] == "external-read-only"
|
||||||
smoke = cast(dict[str, object], acceptance["smoke"])
|
smoke = cast(dict[str, object], acceptance["smoke"])
|
||||||
assert smoke["network"] == "none"
|
assert smoke["network"] == "none"
|
||||||
assert smoke["read_only_rootfs"] is True
|
assert smoke["read_only_rootfs"] is True
|
||||||
@@ -174,16 +205,40 @@ def test_install_plan_requires_offline_build_hardening_smoke_and_unfilled_receip
|
|||||||
"MISSIONCORE_OBSERVATORY_WORKER_BASE_URL": "http://127.0.0.1:18080",
|
"MISSIONCORE_OBSERVATORY_WORKER_BASE_URL": "http://127.0.0.1:18080",
|
||||||
"MISSIONCORE_OBSERVATORY_WORKER_TOKEN_FILE": "/run/secrets/observatory-worker.token",
|
"MISSIONCORE_OBSERVATORY_WORKER_TOKEN_FILE": "/run/secrets/observatory-worker.token",
|
||||||
"MISSIONCORE_OBSERVATORY_WORKER_WORK_ROOT": "/work",
|
"MISSIONCORE_OBSERVATORY_WORKER_WORK_ROOT": "/work",
|
||||||
"MISSIONCORE_OBSERVATORY_WORKER_DEFINITIONS_FILE": (
|
"MISSIONCORE_OBSERVATORY_WORKER_DEFINITIONS_FILE": DEFINITIONS_CONTAINER_PATH,
|
||||||
"/opt/nodedc/mission-core/config/observatory-portable-run-definitions.json"
|
|
||||||
),
|
|
||||||
"MISSIONCORE_OBSERVATORY_WORKER_RUNTIME_REGISTRY_FILE": (
|
"MISSIONCORE_OBSERVATORY_WORKER_RUNTIME_REGISTRY_FILE": (
|
||||||
"/opt/nodedc/mission-core/config/observatory-worker-runtime-candidates.json"
|
RUNTIME_REGISTRY_CONTAINER_PATH
|
||||||
),
|
),
|
||||||
"MISSIONCORE_OBSERVATORY_M49_INSTALLATION_RECEIPT_FILE": (
|
"MISSIONCORE_OBSERVATORY_M49_INSTALLATION_RECEIPT_FILE": (
|
||||||
"/release/worker-installation-receipt.json"
|
"/release/worker-installation-receipt.json"
|
||||||
),
|
),
|
||||||
|
"MISSIONCORE_OBSERVATORY_LAB_V1_INSTALLATION_RECEIPT_FILE": (
|
||||||
|
LAB_V1_RECEIPT_CONTAINER_PATH
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
registry_files = cast(dict[str, object], runtime["runtime_registry_files"])
|
||||||
|
assert registry_files["binding"] == "individual read-only bind files"
|
||||||
|
assert registry_files["identity_timing"] == (
|
||||||
|
"filled and verified after coordinator image build"
|
||||||
|
)
|
||||||
|
assert registry_files["included_in_coordinator_image_or_image_receipt"] is False
|
||||||
|
registry_rows = cast(list[dict[str, object]], registry_files["required"])
|
||||||
|
assert [row["container_path"] for row in registry_rows] == [
|
||||||
|
DEFINITIONS_CONTAINER_PATH,
|
||||||
|
RUNTIME_REGISTRY_CONTAINER_PATH,
|
||||||
|
]
|
||||||
|
assert all(
|
||||||
|
row["host_path"] is None
|
||||||
|
and row["byte_length"] is None
|
||||||
|
and row["sha256"] is None
|
||||||
|
and row["mode"] == "read-only"
|
||||||
|
for row in registry_rows
|
||||||
|
)
|
||||||
|
registry_preflight = cast(list[str], registry_files["required_preflight"])
|
||||||
|
assert any("after the coordinator image identity exists" in row for row in registry_preflight)
|
||||||
|
assert any("symbolic-link" in row for row in registry_preflight)
|
||||||
|
assert any("read-only file" in row for row in registry_preflight)
|
||||||
|
assert any("inside the coordinator image" in row for row in registry_preflight)
|
||||||
user = cast(dict[str, object], runtime["user"])
|
user = cast(dict[str, object], runtime["user"])
|
||||||
assert (user["uid"], user["gid"]) == (0, 0)
|
assert (user["uid"], user["gid"]) == (0, 0)
|
||||||
assert cast(str, user["reason"]).strip()
|
assert cast(str, user["reason"]).strip()
|
||||||
@@ -205,8 +260,8 @@ def test_install_plan_requires_offline_build_hardening_smoke_and_unfilled_receip
|
|||||||
socket_mount = cast(dict[str, object], docker_control["socket_mount"])
|
socket_mount = cast(dict[str, object], docker_control["socket_mount"])
|
||||||
assert socket_mount == {
|
assert socket_mount == {
|
||||||
"type": "bind",
|
"type": "bind",
|
||||||
"host_path": str(local_runners._DOCKER_SOCKET),
|
"host_path": DOCKER_SOCKET,
|
||||||
"container_path": str(local_runners._DOCKER_SOCKET),
|
"container_path": DOCKER_SOCKET,
|
||||||
"mode": "read-write",
|
"mode": "read-write",
|
||||||
"exception_to_read_only_mount_policy": True,
|
"exception_to_read_only_mount_policy": True,
|
||||||
}
|
}
|
||||||
@@ -219,11 +274,18 @@ def test_install_plan_requires_offline_build_hardening_smoke_and_unfilled_receip
|
|||||||
"force-delete exact created container ID",
|
"force-delete exact created container ID",
|
||||||
]
|
]
|
||||||
fences = cast(dict[str, object], docker_control["sibling_runtime_fences"])
|
fences = cast(dict[str, object], docker_control["sibling_runtime_fences"])
|
||||||
assert fences["exact_image_sha256s"] == {
|
assert "exact_image_sha256s" not in fences
|
||||||
"eomt": local_runners._EOMT_IMAGE_SHA256,
|
assert fences["component_image_identity"] == {
|
||||||
"ddrnet": local_runners._DDRNET_IMAGE_SHA256,
|
"source": LAB_V1_RECEIPT_CONTAINER_PATH,
|
||||||
|
"schema_version": (
|
||||||
|
"missioncore.observatory-portable-lab-v1-worker-installation-ready-"
|
||||||
|
"receipt/v1"
|
||||||
|
),
|
||||||
|
"fields": "component_installations.<eomt-or-ddrnet>.image_sha256",
|
||||||
|
"image_kind": "derived adapter image",
|
||||||
|
"base_image_ids_are_component_ids": False,
|
||||||
|
"queued_job_override_allowed": False,
|
||||||
}
|
}
|
||||||
assert local_runners._EOMT_IMAGE_SHA256 == BASE_SHA256
|
|
||||||
assert "queued job" in cast(str, fences["commands_and_entrypoints"])
|
assert "queued job" in cast(str, fences["commands_and_entrypoints"])
|
||||||
assert "exact Worker-host asset roots" in cast(str, fences["bind_sources"])
|
assert "exact Worker-host asset roots" in cast(str, fences["bind_sources"])
|
||||||
assert fences["network"] == "none"
|
assert fences["network"] == "none"
|
||||||
@@ -254,15 +316,32 @@ def test_install_plan_requires_offline_build_hardening_smoke_and_unfilled_receip
|
|||||||
external = cast(dict[str, object], runtime["external_assets"])
|
external = cast(dict[str, object], runtime["external_assets"])
|
||||||
assert external["baked_into_agent_image"] is False
|
assert external["baked_into_agent_image"] is False
|
||||||
assert external["queued_jobs_may_select_paths_or_commands"] is False
|
assert external["queued_jobs_may_select_paths_or_commands"] is False
|
||||||
|
mounts = cast(list[dict[str, object]], runtime["mounts"])
|
||||||
|
registry_mounts = [
|
||||||
|
row
|
||||||
|
for row in mounts
|
||||||
|
if cast(str, row["container_path"]).startswith("/run/nodedc/registries/")
|
||||||
|
]
|
||||||
|
assert registry_mounts == [
|
||||||
|
{
|
||||||
|
"container_path": DEFINITIONS_CONTAINER_PATH,
|
||||||
|
"mode": "read-only",
|
||||||
|
"purpose": "exact external portable RunDefinition registry file",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"container_path": RUNTIME_REGISTRY_CONTAINER_PATH,
|
||||||
|
"mode": "read-only",
|
||||||
|
"purpose": "exact external portable runtime candidate registry file",
|
||||||
|
},
|
||||||
|
]
|
||||||
lab_v1_input = cast(dict[str, object], runtime["lab_v1_runner_installation_input"])
|
lab_v1_input = cast(dict[str, object], runtime["lab_v1_runner_installation_input"])
|
||||||
assert lab_v1_input == {
|
assert lab_v1_input == {
|
||||||
"state": "loader-contract-not-yet-defined",
|
"state": "external-installed-receipt-required",
|
||||||
"environment_variable": None,
|
"environment_variable": "MISSIONCORE_OBSERVATORY_LAB_V1_INSTALLATION_RECEIPT_FILE",
|
||||||
"container_path": None,
|
"container_path": LAB_V1_RECEIPT_CONTAINER_PATH,
|
||||||
"reason": (
|
"mode": "read-only",
|
||||||
"the current local runner module defines an in-memory sealed installation "
|
"owns_component_image_identities": True,
|
||||||
"receipt but no environment loader or installed receipt path"
|
"queued_jobs_may_override_component_images": False,
|
||||||
),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
receipt = cast(dict[str, object], document["receipt_skeleton"])
|
receipt = cast(dict[str, object], document["receipt_skeleton"])
|
||||||
@@ -274,4 +353,5 @@ def test_install_plan_requires_offline_build_hardening_smoke_and_unfilled_receip
|
|||||||
image = cast(dict[str, object], receipt["image"])
|
image = cast(dict[str, object], receipt["image"])
|
||||||
assert image == {"tag": None, "id": None, "size_bytes": None}
|
assert image == {"tag": None, "id": None, "size_bytes": None}
|
||||||
assert receipt["models_baked_into_image"] is False
|
assert receipt["models_baked_into_image"] is False
|
||||||
|
assert receipt["runtime_registries_baked_into_image"] is False
|
||||||
assert receipt["authority"] == AUTHORITY
|
assert receipt["authority"] == AUTHORITY
|
||||||
|
|||||||
Reference in New Issue
Block a user