fix(deploy): allow repeatable typed core releases

This commit is contained in:
Codex
2026-08-13 09:44:07 +03:00
parent 71fff82c99
commit 9c359111ea
3 changed files with 186 additions and 6 deletions
@@ -691,6 +691,167 @@ class DeviceManagerControlPlaneArtifactsTest(unittest.TestCase):
},
)
def test_control_core_release_v2_builder_supports_v2_release_predecessor(self):
with tempfile.TemporaryDirectory(
prefix="nodedc-control-core-v2-successor-",
) as directory:
artifact_dir = Path(directory) / "successor"
environment = os.environ.copy()
environment["NODEDC_DEPLOY_ARTIFACT_DIR"] = str(artifact_dir)
predecessor_id = "device-control-core-release-v2-unit-001"
predecessor_sha = "b" * 64
completed = subprocess.run(
[
"node",
str(
SCRIPT_DIR
/ "build-device-control-core-release-artifact.mjs"
),
"device-control-core-release-v2-unit-002",
predecessor_id,
predecessor_sha,
],
cwd=PLATFORM_ROOT,
env=environment,
check=True,
capture_output=True,
text=True,
)
successor = json.loads(completed.stdout)
extracted = Path(directory) / "extracted-successor"
extracted.mkdir()
_manifest, entries, payload = RUNNER.load_artifact(
Path(successor["artifact"]),
extracted,
)
self.assertEqual(
tuple(entries),
RUNNER.DEVICE_PLANE_CONTROL_CORE_RELEASE_V2_ENTRIES,
)
descriptor = json.loads(
(
payload / RUNNER.DEVICE_PLANE_CONTROL_CORE_RELEASE_V2_REL
).read_text(encoding="utf-8")
)
self.assertEqual(
descriptor["predecessor"],
{
"kind": "release",
"patchId": predecessor_id,
"artifactSha256": predecessor_sha,
},
)
def test_control_core_release_v2_accepts_current_v2_release_predecessor(self):
with tempfile.TemporaryDirectory(
prefix="nodedc-control-core-v2-predecessor-",
) as directory:
root = Path(directory)
applied = root / "applied"
temporary = root / "tmp"
device_plane = root / "device-plane"
for path in (applied, temporary, device_plane / "deployment"):
path.mkdir(parents=True)
predecessor_id = "device-control-core-release-v2-unit-001"
predecessor_sha = "b" * 64
artifact_name = f"nodedc-device-plane-{predecessor_id}.tgz"
(applied / artifact_name).write_bytes(b"reviewed-v2-predecessor")
predecessor = {
"kind": "release",
"patchId": predecessor_id,
"artifactSha256": predecessor_sha,
}
predecessor_descriptor = (
RUNNER.expected_device_plane_control_core_release_descriptor(
predecessor_id,
{
"kind": "release",
"patchId": "device-control-core-release-20260812-024",
"artifactSha256": "a" * 64,
},
schema_version="v2",
)
)
candidate_descriptor = (
RUNNER.expected_device_plane_control_core_release_descriptor(
"device-control-core-release-v2-unit-002",
predecessor,
schema_version="v2",
)
)
installed = (
device_plane / RUNNER.DEVICE_PLANE_CONTROL_CORE_RELEASE_V2_REL
)
installed.write_text(
json.dumps(predecessor_descriptor),
encoding="utf-8",
)
with (
mock.patch.object(RUNNER, "APPLIED_DIR", applied),
mock.patch.object(RUNNER, "TMP_DIR", temporary),
mock.patch.object(RUNNER, "DEVICE_PLANE_ROOT", device_plane),
mock.patch.object(
RUNNER,
"validate_device_plane_control_core_release_payload",
side_effect=(candidate_descriptor, predecessor_descriptor),
),
mock.patch.object(
RUNNER,
"load_artifact",
return_value=(
{
"id": predecessor_id,
"component": "device-plane",
"type": "app-overlay",
},
RUNNER.DEVICE_PLANE_CONTROL_CORE_RELEASE_V2_ENTRIES,
root / "predecessor-payload",
),
),
mock.patch.object(
RUNNER,
"load_state",
return_value=[{
"id": predecessor_id,
"artifact": artifact_name,
"component": "device-plane",
"sha256": predecessor_sha,
"status": "ok",
}],
),
mock.patch.object(
RUNNER,
"sha256_file",
return_value=predecessor_sha,
),
mock.patch.object(
RUNNER,
"collect_exact_files",
return_value={"same": "source"},
),
mock.patch.object(RUNNER, "component_compose_files"),
mock.patch.object(
RUNNER,
"inspect_device_edge_channel_core_identity_state",
return_value="valid-reuse-at-apply",
),
mock.patch.object(RUNNER, "healthcheck_compose_service"),
mock.patch.object(
RUNNER,
"validate_device_manager_control_plane_runtime",
),
):
result = (
RUNNER.validate_device_plane_control_core_release_predecessor(
root / "candidate-payload"
)
)
self.assertEqual(
result["mode"],
"active-device-control-core-forward-release",
)
def test_control_core_release_rejects_direct_legacy_predecessor(self):
with tempfile.TemporaryDirectory(
prefix="nodedc-control-core-release-invalid-",