From 07ffb22d3831a156ec2fbbe2dcbb569f9b0ae5d8 Mon Sep 17 00:00:00 2001 From: DCCONSTRUCTIONS Date: Sat, 22 Aug 2026 10:49:52 +0300 Subject: [PATCH] fix(manager): ship canonical NODE.DC favicon set --- apps/device-manager/index.html | 6 ++ apps/device-manager/public/favicon.ico | Bin 0 -> 16958 bytes .../public/favicon/apple-touch-icon.png | Bin 0 -> 4142 bytes .../device-manager/public/favicon/favicon.ico | Bin 0 -> 16958 bytes .../public/favicon/icon-192.png | Bin 0 -> 4386 bytes .../public/favicon/icon-512.png | Bin 0 -> 13039 bytes .../public/favicon/icon-adaptive.svg | 13 ++++ .../public/favicon/manifest.webmanifest.json | 29 +++++++ deployment/device-manager-release-v6.json | 41 ++++++++++ ...-device-manager-control-plane-artifact.mjs | 72 +++++++++++++++--- ..._device_manager_control_plane_artifacts.py | 71 ++++++++++++++++- 11 files changed, 220 insertions(+), 12 deletions(-) create mode 100644 apps/device-manager/public/favicon.ico create mode 100644 apps/device-manager/public/favicon/apple-touch-icon.png create mode 100644 apps/device-manager/public/favicon/favicon.ico create mode 100644 apps/device-manager/public/favicon/icon-192.png create mode 100644 apps/device-manager/public/favicon/icon-512.png create mode 100644 apps/device-manager/public/favicon/icon-adaptive.svg create mode 100644 apps/device-manager/public/favicon/manifest.webmanifest.json create mode 100644 deployment/device-manager-release-v6.json diff --git a/apps/device-manager/index.html b/apps/device-manager/index.html index 30163c1..bc870e3 100644 --- a/apps/device-manager/index.html +++ b/apps/device-manager/index.html @@ -4,6 +4,12 @@ + + + + + + NODE.DC Device Core diff --git a/apps/device-manager/public/favicon.ico b/apps/device-manager/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..973f3b2db97f00b686175edb7497021fe0f1421d GIT binary patch literal 16958 zcmeI4U5Hd=7{}jfidmD~6|IX*6f)Wnf+Q)(+Cdbxi;&QZK)Oj&H18Baw&oDs3EBsE z;e{-Scp-ux3t3&XQc8hzBS{xa4J68D#MTCGvCjDW&p9uw!#VG1XXmV^nfF=$=b7_9 z&v`!nXU==xGc#yRfxmLuuw8EY*BbMLF{U3dWCEb^hG1JXKSVg-x1IsdfM>un;2H1? zcm_NJo&nE*XTUQsM+|&Sp20cFmA5pjC};{yfE9TwF5`NN#Qz%9Bb?4SU*5v+oYuSL z;LW@hnNdAY5_c@7|53*JGRm2!u*YM1x9@>Nc`7u6S~d`~=IDPC+v*JR<{{*x6mbpM zbDg9w;iLJn)8qphO6s|Jd{2ipzmk6boBpM&OeoVI_W6Pl-oZ7uX} zx!L$X=iqVb|8*Aq|H!eA<&1+~>e&Hy0j=Yjv7504Kynn=a~Y?9!v1rLPk>#r7`z9X z^J!nTyaVQgtmQKj#PwpwhOz7ZwFcaE`0Cl`W$=c>M=>>TYW|!Dt^k`SPU{|%rMyOP z)g6~xV}F3Bz$4%)Nb=M85U_HA7cSo~Bgf~_cO1Ur>bc0b-KvLxX+7rbCkB-Qs1wwI!WXB>VyUhnlJNxQy}MF+l)PO3%YRj>%OLv&8R0m%^jz=LezuOr|$c%7~f(SSFOrP4s^vo z8wFm4)*RsSZKv%|a;=DRt4CLCany=z<{($xaqQ0k%@3DTd|h!`wb^;}MRMzNlcYF$ zmRtg6A`5X&yOuSNNwnTg%ANJNz4i{J)G&m7Ch`f+uG+N@DgmuqT->{2w8Qp0`85wN z0Iu_;`_5YMUt|qVQy{56*Pr z=WlBh2iv=-cX2QZ^f{J9YlBqZYX-?F&@DYr?^Dl5T03fOpx507J!|S7=EXDM z8So5v20R0v0ndPEz%$?(@CcG94$rVuPA(nwDs=p)jIDe|vg5Bf^g9wO-fMtE4d zA@!Om>l@8V%>?=tO+{b!pa&)!zo-cY^ko;aOlg!TEV9~L)h^$OjWm=g1)(lR+WsEL N>d?wIY~{gi?*Ti^k*5Fv literal 0 HcmV?d00001 diff --git a/apps/device-manager/public/favicon/apple-touch-icon.png b/apps/device-manager/public/favicon/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..5078c01653bd8fca4c6ff0d98769b86f54f17743 GIT binary patch literal 4142 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 literal 0 HcmV?d00001 diff --git a/apps/device-manager/public/favicon/favicon.ico b/apps/device-manager/public/favicon/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..973f3b2db97f00b686175edb7497021fe0f1421d GIT binary patch literal 16958 zcmeI4U5Hd=7{}jfidmD~6|IX*6f)Wnf+Q)(+Cdbxi;&QZK)Oj&H18Baw&oDs3EBsE z;e{-Scp-ux3t3&XQc8hzBS{xa4J68D#MTCGvCjDW&p9uw!#VG1XXmV^nfF=$=b7_9 z&v`!nXU==xGc#yRfxmLuuw8EY*BbMLF{U3dWCEb^hG1JXKSVg-x1IsdfM>un;2H1? zcm_NJo&nE*XTUQsM+|&Sp20cFmA5pjC};{yfE9TwF5`NN#Qz%9Bb?4SU*5v+oYuSL z;LW@hnNdAY5_c@7|53*JGRm2!u*YM1x9@>Nc`7u6S~d`~=IDPC+v*JR<{{*x6mbpM zbDg9w;iLJn)8qphO6s|Jd{2ipzmk6boBpM&OeoVI_W6Pl-oZ7uX} zx!L$X=iqVb|8*Aq|H!eA<&1+~>e&Hy0j=Yjv7504Kynn=a~Y?9!v1rLPk>#r7`z9X z^J!nTyaVQgtmQKj#PwpwhOz7ZwFcaE`0Cl`W$=c>M=>>TYW|!Dt^k`SPU{|%rMyOP z)g6~xV}F3Bz$4%)Nb=M85U_HA7cSo~Bgf~_cO1Ur>bc0b-KvLxX+7rbCkB-Qs1wwI!WXB>VyUhnlJNxQy}MF+l)PO3%YRj>%OLv&8R0m%^jz=LezuOr|$c%7~f(SSFOrP4s^vo z8wFm4)*RsSZKv%|a;=DRt4CLCany=z<{($xaqQ0k%@3DTd|h!`wb^;}MRMzNlcYF$ zmRtg6A`5X&yOuSNNwnTg%ANJNz4i{J)G&m7Ch`f+uG+N@DgmuqT->{2w8Qp0`85wN z0Iu_;`_5YMUt|qVQy{56*Pr z=WlBh2iv=-cX2QZ^f{J9YlBqZYX-?F&@DYr?^Dl5T03fOpx507J!|S7=EXDM z8So5v20R0v0ndPEz%$?(@CcG94$rVuPA(nwDs=p)jIDe|vg5Bf^g9wO-fMtE4d zA@!Om>l@8V%>?=tO+{b!pa&)!zo-cY^ko;aOlg!TEV9~L)h^$OjWm=g1)(lR+WsEL N>d?wIY~{gi?*Ti^k*5Fv literal 0 HcmV?d00001 diff --git a/apps/device-manager/public/favicon/icon-192.png b/apps/device-manager/public/favicon/icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..d553a58e81dd92630500cf4bdc2f104993412841 GIT binary patch literal 4386 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 + + + + \ No newline at end of file diff --git a/apps/device-manager/public/favicon/manifest.webmanifest.json b/apps/device-manager/public/favicon/manifest.webmanifest.json new file mode 100644 index 0000000..f7256e8 --- /dev/null +++ b/apps/device-manager/public/favicon/manifest.webmanifest.json @@ -0,0 +1,29 @@ +{ + "theme_color": "#eeeff4", + "background_color": "#eeeff4", + "display": "browser", + "scope": "/", + "start_url": "/", + "icons": [ + { + "src": "icon-adaptive.svg", + "type": "image/svg+xml", + "sizes": "any" + }, + { + "src": "icon-192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "icon-512.png", + "type": "image/png", + "sizes": "512x512" + }, + { + "src": "apple-touch-icon.png", + "type": "image/png", + "sizes": "180x180" + } + ] +} diff --git a/deployment/device-manager-release-v6.json b/deployment/device-manager-release-v6.json new file mode 100644 index 0000000..6f6ba06 --- /dev/null +++ b/deployment/device-manager-release-v6.json @@ -0,0 +1,41 @@ +{ + "schemaVersion": "nodedc.device-plane.device-manager-release.v6", + "releaseId": "__PATCH_ID__", + "action": "upgrade", + "predecessor": { + "kind": "release", + "patchId": "device-manager-release-v5-20260822-034", + "artifactSha256": "acc1d2ae2cda66861054826928c25d01a2428e688cc8132a9c381831bf29ab5a" + }, + "controlCorePredecessor": { + "patchId": "device-control-core-release-v2-20260821-030", + "artifactSha256": "8459521a662541a5a87cb0188991cdcfb51727427db8ec2a232ce4846bfc3454" + }, + "edgeChannelPredecessor": { + "patchId": "device-edge-core-channel-upgrade-v4-20260812-023", + "artifactSha256": "c10d5b6b7d55ab239f85b6c8130e34ce9f84985e3b46e6e5534733156c7982fc" + }, + "service": "device-manager", + "publicIngress": "reverse-proxy-only", + "deviceCoreManagementApi": "file-token-authenticated", + "launcherTrust": "file-token-scoped-to-device-core-handoff", + "edgeChannel": "preserve-active-v4-core-initiated-pinned-mtls", + "edgeChannelIdentity": "reuse-runner-managed-host-local-private-key-public-certificate-export", + "edgeChannelEgress": "preserve-dedicated-core-only-bridge-no-host-ingress-public-ipv4-tcp-443-only", + "healthGate": "bounded-container-grace+core-contract+persistent-data", + "commandTransport": "typed-service-ping-v1", + "commandCatalog": "allowlisted-adapter-typed-commands-only", + "credentialBoundary": "transient-core-memory-then-single-pinned-mtls-command-envelope-to-edge-never-persisted-never-logged-never-returned", + "presentationPersistence": "runner-managed-host-data-bind", + "presentationDataHostPath": "/volume1/docker/nodedc-device-plane/data/device-manager", + "presentationDataContainerPath": "/var/lib/nodedc-device-manager", + "presentationDataOwnership": "uid-1000-gid-1000-mode-0750", + "presentationDataLifecycle": "preserve-across-manager-recreate-and-source-rollback", + "presentationPath": "/var/lib/nodedc-device-manager/device-manager-presentation.json", + "mediaRoot": "/var/lib/nodedc-device-manager/media", + "defaultAccentHex": "#f5f5f5", + "overviewLayout": "mission-core-landing-stage-v1", + "faviconSet": "nodedc-adaptive-v1", + "gelios": "untouched-legacy-only", + "rollback": "restore-preapply-snapshot-preserve-manager-data" +} 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 19577f4..5b00307 100644 --- a/infra/deploy-runner/build-device-manager-control-plane-artifact.mjs +++ b/infra/deploy-runner/build-device-manager-control-plane-artifact.mjs @@ -11,21 +11,24 @@ const platformRoot = resolve(scriptDir, "../.."); const devicePlaneRoot = platformRoot; const managerRoot = resolve(platformRoot, "apps/device-manager"); const artifactDir = resolve(process.env.NODEDC_DEPLOY_ARTIFACT_DIR || resolve(scriptDir, "../deploy-artifacts")); -const [patchId = "device-manager-release-v5-20260822-034", ...extra] = process.argv.slice(2); +const [patchId = "device-manager-release-v6-20260822-035", ...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 descriptorPath = patchId.startsWith("device-manager-release-v5-") - ? "deployment/device-manager-release-v5.json" - : patchId.startsWith("device-manager-release-v4-") - ? "deployment/device-manager-release-v4.json" - : patchId.startsWith("device-manager-release-v3-") - ? "deployment/device-manager-release-v3.json" - : "deployment/device-manager-release-v1.json"; +const descriptorPath = patchId.startsWith("device-manager-release-v6-") + ? "deployment/device-manager-release-v6.json" + : patchId.startsWith("device-manager-release-v5-") + ? "deployment/device-manager-release-v5.json" + : patchId.startsWith("device-manager-release-v4-") + ? "deployment/device-manager-release-v4.json" + : patchId.startsWith("device-manager-release-v3-") + ? "deployment/device-manager-release-v3.json" + : "deployment/device-manager-release-v1.json"; const isV3 = descriptorPath.endsWith("release-v3.json"); const isV4 = descriptorPath.endsWith("release-v4.json"); const isV5 = descriptorPath.endsWith("release-v5.json"); -const isPersistent = isV4 || isV5; +const isV6 = descriptorPath.endsWith("release-v6.json"); +const isPersistent = isV4 || isV5 || isV6; const isManagerOnly = isV3 || isPersistent; const composeSource = resolve(devicePlaneRoot, "docker-compose.device-manager.yml"); const composeSourceSha256 = createHash("sha256").update(await readFile(composeSource)).digest("hex"); @@ -164,7 +167,56 @@ try { : "restore-preapply-snapshot") ); if (commonContractInvalid) throw new Error("device_manager_activation_successor_contract_mismatch"); - if (descriptorPath.endsWith("release-v5.json")) { + if (descriptorPath.endsWith("release-v6.json")) { + if ( + descriptor.schemaVersion !== "nodedc.device-plane.device-manager-release.v6" + || descriptor.predecessor?.kind !== "release" + || descriptor.predecessor?.patchId !== "device-manager-release-v5-20260822-034" + || descriptor.predecessor?.artifactSha256 !== "acc1d2ae2cda66861054826928c25d01a2428e688cc8132a9c381831bf29ab5a" + || descriptor.commandTransport !== "typed-service-ping-v1" + || descriptor.commandCatalog !== "allowlisted-adapter-typed-commands-only" + || descriptor.credentialBoundary !== "transient-core-memory-then-single-pinned-mtls-command-envelope-to-edge-never-persisted-never-logged-never-returned" + || descriptor.controlCorePredecessor?.patchId !== "device-control-core-release-v2-20260821-030" + || descriptor.controlCorePredecessor?.artifactSha256 !== "8459521a662541a5a87cb0188991cdcfb51727427db8ec2a232ce4846bfc3454" + || descriptor.edgeChannelPredecessor?.patchId !== "device-edge-core-channel-upgrade-v4-20260812-023" + || descriptor.edgeChannelPredecessor?.artifactSha256 !== "c10d5b6b7d55ab239f85b6c8130e34ce9f84985e3b46e6e5534733156c7982fc" + || descriptor.presentationPersistence !== "runner-managed-host-data-bind" + || descriptor.presentationDataHostPath !== "/volume1/docker/nodedc-device-plane/data/device-manager" + || descriptor.presentationDataContainerPath !== "/var/lib/nodedc-device-manager" + || descriptor.presentationDataOwnership !== "uid-1000-gid-1000-mode-0750" + || descriptor.presentationDataLifecycle !== "preserve-across-manager-recreate-and-source-rollback" + || descriptor.presentationPath !== "/var/lib/nodedc-device-manager/device-manager-presentation.json" + || descriptor.mediaRoot !== "/var/lib/nodedc-device-manager/media" + || descriptor.defaultAccentHex !== "#f5f5f5" + || descriptor.overviewLayout !== "mission-core-landing-stage-v1" + || descriptor.faviconSet !== "nodedc-adaptive-v1" + || descriptor.rollback !== "restore-preapply-snapshot-preserve-manager-data" + || descriptor.gelios !== "untouched-legacy-only" + ) throw new Error("device_manager_v6_favicon_contract_mismatch"); + const faviconHashes = { + "favicon.ico": "f8933114a85646335ea5c94944f56d3cd8c48a6032016719f7905ff244ec0aa2", + "favicon/favicon.ico": "f8933114a85646335ea5c94944f56d3cd8c48a6032016719f7905ff244ec0aa2", + "favicon/icon-adaptive.svg": "481984e83997d786bb0a72ad1ee80037db13aef3a0792ab3109df95c2199b38e", + "favicon/apple-touch-icon.png": "afdccc28152a566e264e533ca218362f05d5bcec936c647f9a54f414c0bd4763", + "favicon/icon-192.png": "5b10a24feb4754f15c69761cef42f91a01f885d04095156b1a12e254875fdd4d", + "favicon/icon-512.png": "f98bac3dba59b7eefbe89f8bb8abc25567226a54ab7ed3b6b1a4caffbdd9ee15", + "favicon/manifest.webmanifest.json": "2a8ecdc6e6c64833f812ae02bbc0c7bd9b435e0cfa75cc21d6edf054d41275fc", + }; + for (const [relativePath, expectedSha256] of Object.entries(faviconHashes)) { + const content = await readFile(join(payload, "services/device-manager/dist", relativePath)); + const actualSha256 = createHash("sha256").update(content).digest("hex"); + if (actualSha256 !== expectedSha256) throw new Error(`device_manager_v6_favicon_hash_mismatch:${relativePath}`); + } + const indexHtml = await readFile(join(payload, "services/device-manager/dist/index.html"), "utf8"); + for (const requiredLink of [ + 'href="/favicon/icon-adaptive.svg"', + 'href="/favicon/favicon.ico"', + 'href="/favicon/apple-touch-icon.png"', + 'href="/favicon/icon-192.png"', + 'href="/favicon/icon-512.png"', + 'href="/favicon/manifest.webmanifest.json"', + ]) if (!indexHtml.includes(requiredLink)) throw new Error(`device_manager_v6_favicon_link_missing:${requiredLink}`); + } else if (descriptorPath.endsWith("release-v5.json")) { if ( descriptor.schemaVersion !== "nodedc.device-plane.device-manager-release.v5" || descriptor.predecessor?.kind !== "release" 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 240d8ed..5b0f0e9 100644 --- a/infra/deploy-runner/test_device_manager_control_plane_artifacts.py +++ b/infra/deploy-runner/test_device_manager_control_plane_artifacts.py @@ -458,10 +458,15 @@ class DeviceManagerControlPlaneArtifactsTest(unittest.TestCase): self.assertEqual(manifest["component"], "device-plane") self.assertEqual(result["services"], ["device-manager"]) self.assertFalse( - any(name.startswith("payload/services/device-control-core/") for name in names) + any( + name.startswith("payload/services/device-control-core/") + for name in names + ) ) self.assertFalse(any(name.startswith("payload/packages/") for name in names)) - self.assertFalse(any(name.endswith((".test.mjs", ".map")) for name in names)) + self.assertFalse( + any(name.endswith((".test.mjs", ".map")) for name in names) + ) template = json.loads( ( DEVICE_CORE_ROOT @@ -503,6 +508,68 @@ class DeviceManagerControlPlaneArtifactsTest(unittest.TestCase): ) ) + def test_device_manager_release_v6_includes_canonical_favicon_set(self): + patch_id = "device-manager-release-v6-unit-001" + manifest, entries, names, result = self.assert_deterministic_artifact( + "build-device-manager-control-plane-artifact.mjs", + patch_id, + RUNNER.DEVICE_PLANE_MANAGER_RELEASE_V6_ENTRIES, + ) + self.assertEqual(manifest["component"], "device-plane") + self.assertEqual(result["services"], ["device-manager"]) + self.assertFalse( + any(name.startswith("payload/services/device-control-core/") for name in names) + ) + self.assertFalse(any(name.startswith("payload/packages/") for name in names)) + self.assertFalse(any(name.endswith((".test.mjs", ".map")) for name in names)) + for name in ( + "payload/services/device-manager/dist/favicon.ico", + "payload/services/device-manager/dist/favicon/favicon.ico", + "payload/services/device-manager/dist/favicon/icon-adaptive.svg", + "payload/services/device-manager/dist/favicon/apple-touch-icon.png", + "payload/services/device-manager/dist/favicon/icon-192.png", + "payload/services/device-manager/dist/favicon/icon-512.png", + "payload/services/device-manager/dist/favicon/manifest.webmanifest.json", + ): + self.assertIn(name, names) + template = json.loads( + ( + DEVICE_CORE_ROOT + / "deployment/device-manager-release-v6.json" + ).read_text(encoding="utf-8") + ) + descriptor = {**template, "releaseId": patch_id} + self.assertIs( + RUNNER.validate_device_plane_manager_release_descriptor( + descriptor, + schema_version=( + "nodedc.device-plane.device-manager-release.v6" + ), + boundaries=( + RUNNER.expected_device_plane_manager_release_v6_boundaries() + ), + expected_release_id=patch_id, + ), + descriptor, + ) + self.assertEqual(descriptor["faviconSet"], "nodedc-adaptive-v1") + self.assertEqual( + descriptor["predecessor"], + { + "kind": "release", + "patchId": "device-manager-release-v5-20260822-034", + "artifactSha256": ( + "acc1d2ae2cda66861054826928c25d01a2428e688cc8132a9c381831bf29ab5a" + ), + }, + ) + self.assertTrue( + RUNNER.is_device_plane_manager_release_v6_slice( + "device-plane", + entries, + ) + ) + def test_historical_manager_builder_fails_closed_after_v4_compose(self): if self.historical_manager_compose_is_current(): self.skipTest("historical Manager Compose is still current")