diff --git a/infra/deploy-runner/build-device-manager-control-plane-artifact.mjs b/infra/deploy-runner/build-device-manager-control-plane-artifact.mjs index 432d50b..172f931 100644 --- a/infra/deploy-runner/build-device-manager-control-plane-artifact.mjs +++ b/infra/deploy-runner/build-device-manager-control-plane-artifact.mjs @@ -12,7 +12,7 @@ const devicePlaneRoot = resolve(platformRoot, "device-plane"); const designRoot = resolve(process.env.NODEDC_DEVICE_MANAGER_SOURCE_ROOT || resolve(platformRoot, "../NODEDC_DESIGN_GUIDELINE")); const managerRoot = resolve(designRoot, "apps/device-manager"); const artifactDir = resolve(process.env.NODEDC_DEPLOY_ARTIFACT_DIR || resolve(scriptDir, "../deploy-artifacts")); -const [patchId = "device-manager-release-20260811-014", ...extra] = process.argv.slice(2); +const [patchId = "device-manager-release-20260811-015", ...extra] = process.argv.slice(2); if (extra.length || !/^[A-Za-z0-9._-]{1,96}$/.test(patchId)) throw new Error("usage: build-device-manager-control-plane-artifact.mjs [patch-id]"); const entries = [ @@ -22,10 +22,13 @@ const entries = [ "docker-compose.device-manager.yml", "packages/device-protocol-contract", "packages/device-edge-channel-contract", + "packages/device-adapter-runtime/package.json", + "packages/device-adapter-catalog/package.json", "packages/arusnavi-b2-adapter", "services/device-control-core", "services/device-gateway/package.json", "services/device-edge-relay/package.json", + "services/device-gateway-core", "services/device-manager", "deployment/device-manager-release-v2.json", ]; @@ -62,6 +65,14 @@ try { } await copySafe(resolve(devicePlaneRoot, entry), join(payload, entry), devicePlaneRoot); } + await validateDockerCopySources( + join(payload, "services/device-control-core/Dockerfile"), + payload, + ); + await validateDockerCopySources( + join(payload, "services/device-manager/Dockerfile"), + join(payload, "services/device-manager"), + ); for (const modulePath of [ "services/device-control-core/src/sensitive-reference-management.mjs", "packages/device-edge-channel-contract/src/index.mjs", @@ -168,6 +179,40 @@ async function copySafe(source, destination, sourceBoundary) { } } +async function validateDockerCopySources(dockerfilePath, buildContext) { + const dockerfile = await readFile(dockerfilePath, "utf8"); + for (const [index, rawLine] of dockerfile.split("\n").entries()) { + const line = rawLine.trim(); + if (!/^COPY\s+/i.test(line)) continue; + if (line.endsWith("\\") || /^COPY\s+\[/i.test(line)) { + throw new Error(`unsupported_docker_copy_syntax:${dockerfilePath}:${index + 1}`); + } + const tokens = line.split(/\s+/).slice(1); + while (tokens[0]?.startsWith("--")) tokens.shift(); + if (tokens.length < 2) { + throw new Error(`invalid_docker_copy:${dockerfilePath}:${index + 1}`); + } + for (const source of tokens.slice(0, -1)) { + if (/[*?[\]{}]/.test(source)) { + throw new Error(`docker_copy_glob_rejected:${dockerfilePath}:${index + 1}:${source}`); + } + const resolvedSource = resolve(buildContext, source); + const relativeSource = relative(buildContext, resolvedSource); + if (!relativeSource || relativeSource.startsWith("..") || resolve(buildContext, relativeSource) !== resolvedSource) { + throw new Error(`docker_copy_source_outside_context:${dockerfilePath}:${index + 1}:${source}`); + } + try { + await lstat(resolvedSource); + } catch (error) { + if (error?.code === "ENOENT") { + throw new Error(`docker_copy_source_missing:${dockerfilePath}:${index + 1}:${source}`); + } + throw error; + } + } + } +} + function canonicalTarScript() { return [ "import gzip,io,pathlib,sys,tarfile", diff --git a/infra/deploy-runner/nodedc-deploy b/infra/deploy-runner/nodedc-deploy index 4816cb6..0f21819 100755 --- a/infra/deploy-runner/nodedc-deploy +++ b/infra/deploy-runner/nodedc-deploy @@ -299,10 +299,13 @@ DEVICE_PLANE_MANAGER_RELEASE_V2_ENTRIES = ( DEVICE_PLANE_MANAGER_COMPOSE_REL, "packages/device-protocol-contract", "packages/device-edge-channel-contract", + "packages/device-adapter-runtime/package.json", + "packages/device-adapter-catalog/package.json", "packages/arusnavi-b2-adapter", "services/device-control-core", "services/device-gateway/package.json", "services/device-edge-relay/package.json", + "services/device-gateway-core", "services/device-manager", DEVICE_PLANE_MANAGER_RELEASE_V2_REL, ) @@ -3533,10 +3536,13 @@ def allowed_payload_path(component, rel): DEVICE_PLANE_MANAGER_V2_RECONCILIATION_REL, "packages/device-protocol-contract", "packages/device-edge-channel-contract", + "packages/device-adapter-runtime/package.json", + "packages/device-adapter-catalog/package.json", "packages/arusnavi-b2-adapter", "services/device-control-core", "services/device-gateway", "services/device-edge-relay/package.json", + "services/device-gateway-core", "services/device-manager", "services/device-backhaul-target", ): @@ -3547,6 +3553,7 @@ def allowed_payload_path(component, rel): "packages/arusnavi-b2-adapter/", "services/device-control-core/", "services/device-gateway/", + "services/device-gateway-core/", "services/device-manager/", "services/device-backhaul-target/", )): diff --git a/infra/deploy-runner/test_device_manager_control_plane_artifacts.py b/infra/deploy-runner/test_device_manager_control_plane_artifacts.py index a725c5d..15a4249 100644 --- a/infra/deploy-runner/test_device_manager_control_plane_artifacts.py +++ b/infra/deploy-runner/test_device_manager_control_plane_artifacts.py @@ -210,6 +210,18 @@ class DeviceManagerControlPlaneArtifactsTest(unittest.TestCase): names, ) self.assertIn("packages/device-edge-channel-contract", entries) + self.assertIn( + "payload/packages/device-adapter-runtime/package.json", + names, + ) + self.assertIn( + "payload/packages/device-adapter-catalog/package.json", + names, + ) + self.assertIn( + "payload/services/device-gateway-core/src/runtime.mjs", + names, + ) self.assertFalse(any(name.endswith(".test.mjs") for name in names)) self.assertEqual(result["services"], ["device-control-core", "device-manager"]) self.assertNotIn("device-postgres", result["services"]) diff --git a/infra/deploy-runner/test_device_plane_registry.py b/infra/deploy-runner/test_device_plane_registry.py index 4e4e4b4..7837e70 100644 --- a/infra/deploy-runner/test_device_plane_registry.py +++ b/infra/deploy-runner/test_device_plane_registry.py @@ -108,8 +108,11 @@ class DevicePlaneRegistryTest(unittest.TestCase): "docker-compose.device-plane.yml", "packages/device-protocol-contract/src/index.mjs", "packages/device-edge-channel-contract/src/index.mjs", + "packages/device-adapter-runtime/package.json", + "packages/device-adapter-catalog/package.json", "services/device-control-core/Dockerfile", "services/device-gateway/src/runtime.mjs", + "services/device-gateway-core/src/runtime.mjs", ): self.assertTrue( RUNNER.allowed_payload_path("device-plane", allowed),