import hashlib import importlib.machinery import importlib.util import json import os from pathlib import Path import subprocess import tarfile import tempfile import unittest from unittest import mock SCRIPT_DIR = Path(__file__).resolve().parent RUNNER_PATH = SCRIPT_DIR / "nodedc-deploy" BUILDER_PATH = SCRIPT_DIR / "build-engine-composite-provider-v4-artifact.mjs" ENGINE_ROOT = SCRIPT_DIR.parent.parent.parent / "NODEDC_ENGINE_INFRA" PATCH_ID = "engine-composite-provider-v4-20991231-999" def load_runner(): loader = importlib.machinery.SourceFileLoader( "nodedc_engine_composite_provider_v4", str(RUNNER_PATH), ) spec = importlib.util.spec_from_loader(loader.name, loader) module = importlib.util.module_from_spec(spec) loader.exec_module(module) return module RUNNER = load_runner() class EngineCompositeProviderV4Test(unittest.TestCase): def test_predecessor_map_matches_the_applied_release_order(self): self.assertEqual( RUNNER.ENGINE_COMPOSITE_PROVIDER_V4_PREDECESSOR_SHA256, { "nodedc-source/server/assets/provider-packages/v1/catalog.json": "992159fc457ec76ce1f45aad337604c8a72b29252d44fbccda515f0fd6ea6428", "nodedc-source/server/dataProductPublishGrant/providerCatalog.js": "901b8fad80018ce177b34ced804b39cb140a47e831414057f484296b373c651d", "nodedc-source/server/dataProductPublishGrant/service.js": "6a417b25b080c05b40c771df4e2dca163491af2c9083ff73dc7e54ad3b360241", "nodedc-source/server/dataProductPublishGrant/store.js": "a92303b2732e21f68c1ac732fa26e4983cbadf3515741cee983b916a283d754c", }, ) def build(self, artifact_dir): environment = os.environ.copy() environment["NODEDC_ENGINE_SOURCE_ROOT"] = str(ENGINE_ROOT) environment["NODEDC_DEPLOY_ARTIFACT_DIR"] = str(artifact_dir) completed = subprocess.run( ["node", str(BUILDER_PATH), PATCH_ID], check=True, capture_output=True, text=True, env=environment, ) return json.loads(completed.stdout) def test_builder_is_deterministic_and_emits_exact_backend_only_slice(self): current_sha256 = { relative_path: hashlib.sha256((ENGINE_ROOT / relative_path).read_bytes()).hexdigest() for relative_path in RUNNER.ENGINE_COMPOSITE_PROVIDER_V4_ARTIFACT_ENTRIES } if current_sha256 != RUNNER.ENGINE_COMPOSITE_PROVIDER_V4_TARGET_SHA256: self.skipTest("historical v4 builder source has advanced to its exact successor") with tempfile.TemporaryDirectory(prefix="nodedc-engine-composite-v4-") as directory: root = Path(directory) first = self.build(root / "first") second = self.build(root / "second") first_artifact = Path(first["artifact"]) second_artifact = Path(second["artifact"]) self.assertEqual(first_artifact.read_bytes(), second_artifact.read_bytes()) self.assertEqual( first["sha256"], hashlib.sha256(first_artifact.read_bytes()).hexdigest(), ) self.assertEqual(first["services"], ["nodedc-backend"]) self.assertEqual(first["credentialValues"], "preserved") self.assertEqual( tuple(first["entries"]), RUNNER.ENGINE_COMPOSITE_PROVIDER_V4_ARTIFACT_ENTRIES, ) extract = root / "extract" with tarfile.open(first_artifact, "r:gz") as archive: archive.extractall(extract, filter="data") entries = tuple( (extract / "files.txt").read_text(encoding="utf-8").splitlines() ) payload = extract / "payload" self.assertTrue(RUNNER.is_engine_composite_provider_v4_slice("engine", entries)) self.assertEqual(RUNNER.component_services("engine", entries), ("nodedc-backend",)) self.assertEqual( RUNNER.component_healthchecks("engine", entries, ("nodedc-backend",)), ("http://127.0.0.1:3001/health",), ) RUNNER.validate_engine_composite_provider_v4_slice(payload, entries) for relative_path, expected in RUNNER.ENGINE_COMPOSITE_PROVIDER_V4_TARGET_SHA256.items(): self.assertEqual( hashlib.sha256((payload / relative_path).read_bytes()).hexdigest(), expected, ) def test_preflight_requires_every_exact_predecessor_and_immutable_backend(self): with tempfile.TemporaryDirectory(prefix="nodedc-engine-composite-v4-preflight-") as directory: root = Path(directory) for relative_path in RUNNER.ENGINE_COMPOSITE_PROVIDER_V4_ARTIFACT_ENTRIES: path = root / relative_path path.parent.mkdir(parents=True, exist_ok=True) path.write_text("predecessor\n", encoding="utf-8") def exact_sha(path): relative_path = Path(path).relative_to(root).as_posix() return RUNNER.ENGINE_COMPOSITE_PROVIDER_V4_PREDECESSOR_SHA256[relative_path] with ( mock.patch.object(RUNNER, "component_root", return_value=root), mock.patch.object(RUNNER, "sha256_file", side_effect=exact_sha), mock.patch.object( RUNNER, "preflight_engine_credential_backend_runtime", return_value={"mode": "verified-derived-retry"}, ), ): result = RUNNER.preflight_engine_composite_provider_v4_predecessor() self.assertEqual(result["mode"], "exact-composite-provider-v3-to-v4") self.assertEqual( result["predecessor_sha256"], RUNNER.ENGINE_COMPOSITE_PROVIDER_V4_PREDECESSOR_SHA256, ) self.assertEqual( result["target_sha256"], RUNNER.ENGINE_COMPOSITE_PROVIDER_V4_TARGET_SHA256, ) drift_path = root / RUNNER.ENGINE_COMPOSITE_PROVIDER_V4_ARTIFACT_ENTRIES[1] def drift_sha(path): if Path(path) == drift_path: return "0" * 64 return exact_sha(path) with ( mock.patch.object(RUNNER, "component_root", return_value=root), mock.patch.object(RUNNER, "sha256_file", side_effect=drift_sha), ): with self.assertRaises(RUNNER.DeployError): RUNNER.preflight_engine_composite_provider_v4_predecessor() if __name__ == "__main__": unittest.main(verbosity=2)