feat(device-plane): add canonical Device Manager runtime

This commit is contained in:
Codex
2026-08-10 22:00:59 +03:00
parent 1d1e9a96b3
commit 29ba5de92e
14 changed files with 1122 additions and 10 deletions
@@ -0,0 +1,10 @@
{
"schemaVersion": "nodedc.device-plane.device-manager-control-plane.v1",
"action": "activate",
"service": "device-manager",
"publicIngress": "reverse-proxy-only",
"deviceCoreManagementApi": "file-token-authenticated",
"launcherTrust": "file-token-scoped-to-device-core-handoff",
"commandTransport": "disabled",
"gelios": "untouched"
}
@@ -0,0 +1,76 @@
services:
device-control-core:
environment:
DEVICE_MANAGEMENT_API_ENABLED: "true"
DEVICE_MANAGEMENT_CORE_TOKEN_FILE: /run/nodedc-secrets/management-core-token
volumes:
- type: bind
source: /volume1/docker/nodedc-device-plane/secrets/management-core-token
target: /run/nodedc-secrets/management-core-token
read_only: true
bind:
create_host_path: false
device-manager:
image: nodedc/device-manager:local
pull_policy: never
build:
context: ./services/device-manager
restart: unless-stopped
user: "1000:1000"
read_only: true
tmpfs:
- /tmp:size=16m,mode=1777
environment:
NODE_ENV: production
HOST: 0.0.0.0
PORT: "18122"
NODEDC_DEVICE_MANAGER_AUTH_REQUIRED: "true"
NODEDC_DEVICE_MANAGER_COOKIE_SECURE: "true"
NODEDC_DEVICE_MANAGER_LOCAL_PREVIEW: "false"
NODEDC_DEVICE_MANAGER_SERVICE_SLUG: device-core
NODEDC_LAUNCHER_BASE_URL: https://hub.nodedc.ru
NODEDC_LAUNCHER_INTERNAL_URL: http://launcher:5173
NODEDC_LAUNCHER_INTERNAL_TOKEN_FILE: /run/nodedc-secrets/device-core-internal-token
NODEDC_DEVICE_CORE_INTERNAL_URL: http://device-control-core:18120
NODEDC_DEVICE_CORE_TOKEN_FILE: /run/nodedc-secrets/management-core-token
volumes:
- type: bind
source: /volume1/docker/nodedc-platform/secrets/device-core-internal-token
target: /run/nodedc-secrets/device-core-internal-token
read_only: true
bind:
create_host_path: false
- type: bind
source: /volume1/docker/nodedc-device-plane/secrets/management-core-token
target: /run/nodedc-secrets/management-core-token
read_only: true
bind:
create_host_path: false
expose:
- "18122"
networks:
- device-plane-private
- platform-edge
depends_on:
device-control-core:
condition: service_healthy
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
healthcheck:
test:
- CMD
- node
- -e
- fetch('http://127.0.0.1:18122/healthz').then(r=>r.json()).then(v=>{if(!v.ok||!v.authRequired||!v.deviceCoreConfigured)process.exit(1)}).catch(()=>process.exit(1))
interval: 10s
timeout: 5s
retries: 12
start_period: 10s
networks:
platform-edge:
external: true
name: nodedc-platform_edge
@@ -5,7 +5,7 @@ import test from "node:test";
const appUrl = new URL("../src/app.mjs", import.meta.url);
const serverUrl = new URL("../src/server.mjs", import.meta.url);
const repositoryUrl = new URL("../src/postgres-repository.mjs", import.meta.url);
const composeUrl = new URL("../../../docker-compose.device-plane.yml", import.meta.url);
const managerComposeUrl = new URL("../../../docker-compose.device-manager.yml", import.meta.url);
test("management surface is internal, POST-only and disabled by default", async () => {
const source = await readFile(appUrl, "utf8");
@@ -22,14 +22,22 @@ test("management surface is internal, POST-only and disabled by default", async
assert.doesNotMatch(source, /device-commands:(?:plan|confirm|dispatch)/);
});
test("management token remains file-backed and is not enabled by current Compose", async () => {
test("management API is enabled only through a runner-owned file token", async () => {
const server = await readFile(serverUrl, "utf8");
const compose = await readFile(composeUrl, "utf8");
const compose = await readFile(managerComposeUrl, "utf8");
assert.match(server, /DEVICE_MANAGEMENT_API_ENABLED/);
assert.match(server, /DEVICE_MANAGEMENT_CORE_TOKEN_FILE/);
assert.doesNotMatch(compose, /DEVICE_MANAGEMENT_API_ENABLED/);
assert.doesNotMatch(compose, /DEVICE_MANAGEMENT_CORE_TOKEN_FILE/);
assert.match(compose, /DEVICE_MANAGEMENT_API_ENABLED: "true"/);
assert.match(
compose,
/DEVICE_MANAGEMENT_CORE_TOKEN_FILE: \/run\/nodedc-secrets\/management-core-token/,
);
assert.match(
compose,
/source: \/volume1\/docker\/nodedc-device-plane\/secrets\/management-core-token/,
);
assert.doesNotMatch(compose, /DEVICE_MANAGEMENT_CORE_TOKEN:\s/);
});
test("repository pins idempotency, audit and last-owner checks inside one transaction", async () => {
@@ -0,0 +1,16 @@
FROM node:22-alpine
ENV NODE_ENV=production
ENV HOST=0.0.0.0
ENV PORT=18122
WORKDIR /app
COPY server ./server
COPY dist ./dist
USER node
EXPOSE 18122
CMD ["node", "server/device-manager-server.mjs"]