feat(core): add ontology-backed asset and host runtime

This commit is contained in:
DCCONSTRUCTIONS
2026-08-22 14:47:44 +03:00
parent 6ed4414a97
commit b302b6ba1a
13 changed files with 1959 additions and 89 deletions
@@ -8,7 +8,7 @@ const replayedIntermediateConstraintMigrations = Object.freeze([
"009_device_sensitive_reference_commands.sql",
"011_device_control_resource_commands.sql",
]);
const finalCommandKindMigration = "014_device_registry_profile_commands.sql";
const finalCommandKindMigration = "016_device_asset_infrastructure_ontology.sql";
const finalCommandKinds = Object.freeze([
"owner_scope.ensure",
"project.ensure",
@@ -31,6 +31,14 @@ const finalCommandKinds = Object.freeze([
"device_binding.revoke",
"device_configuration_revision.create",
"device_configuration_desired.set",
"asset.ensure",
"asset_binding.ensure",
"asset_binding.close",
"infrastructure_host.ensure",
"infrastructure_endpoint.ensure",
"infrastructure_deployment.ensure",
"infrastructure_service_instance.ensure",
"health_observation.record",
]);
const migrationUrl = new URL(
"../migrations/003_device_management_commands.sql",
@@ -0,0 +1,97 @@
import assert from "node:assert/strict";
import test from "node:test";
import { createControlCoreApp } from "../src/app.mjs";
const managementToken = "test-only-management-token-with-32-bytes";
const identifierPepper = "test-only-identifier-pepper-with-32-bytes";
const projectId = "11111111-1111-4111-8111-111111111111";
test("management API forwards a canonical asset command", async () => {
let executed;
const runtime = await startServer({
executeManagementCommand: async (input) => {
executed = input;
return { replayed: false, result: { created: true } };
},
});
try {
const response = await fetch(`${runtime.baseUrl}/internal/v1/management/assets:ensure`, {
method: "POST",
headers: managementHeaders("ontology-asset-0001"),
body: JSON.stringify({
projectRef: `project:${projectId}`,
assetKey: "trike-001",
displayName: "Trike 001",
assetTypeRef: "asset-type:delivery-trike",
}),
});
assert.equal(response.status, 200);
assert.equal(executed.commandKind, "asset.ensure");
assert.equal(executed.command.assetKey, "trike-001");
} finally {
await runtime.close();
}
});
test("query API exposes the ontology projection through Core", async () => {
let actor;
const runtime = await startServer({
getProjectOntologyProjection: async (value, requestedProjectId) => {
actor = value;
assert.equal(requestedProjectId, projectId);
return {
ontology: { catalogHash: "229c61c02a790906" },
assets: [],
hosts: [],
};
},
});
try {
const response = await fetch(
`${runtime.baseUrl}/internal/v1/query/projects/${projectId}/ontology`,
{ headers: managementHeaders("ontology-query-0001") },
);
const body = await response.json();
assert.equal(response.status, 200);
assert.equal(body.projection.ontology.catalogHash, "229c61c02a790906");
assert.equal(actor.userRef, "user:test-owner");
} finally {
await runtime.close();
}
});
async function startServer(repositoryOverrides) {
const server = createControlCoreApp({
managementApiEnabled: true,
managementToken,
identifierPepper,
repository: {
health: async () => "ready",
executeManagementCommand: async () => ({ replayed: false, result: {} }),
...repositoryOverrides,
},
});
await new Promise((resolve, reject) => {
server.once("error", reject);
server.listen(0, "127.0.0.1", resolve);
});
const address = server.address();
return {
baseUrl: `http://127.0.0.1:${address.port}`,
close: () => new Promise((resolve, reject) =>
server.close((error) => error ? reject(error) : resolve())),
};
}
function managementHeaders(idempotencyKey) {
return {
Authorization: `Bearer ${managementToken}`,
"Content-Type": "application/json",
"Idempotency-Key": idempotencyKey,
"X-NODEDC-User-Ref": "user:test-owner",
"X-NODEDC-Hub-Role": "owner",
"X-NODEDC-Group-Refs": "",
"X-NODEDC-Owner-Scopes": "company=organization:test",
};
}
@@ -0,0 +1,154 @@
import assert from "node:assert/strict";
import test from "node:test";
import {
DEVICE_ONTOLOGY_CATALOG_HASH,
normalizeOntologyManagementCommand,
} from "../src/ontology-management.mjs";
import {
ALL_DEVICE_MANAGEMENT_COMMAND_KINDS,
normalizeDeviceManagementCommand,
} from "../src/management-command.mjs";
const projectRef = "project:11111111-1111-4111-8111-111111111111";
const deviceRef = "device:22222222-2222-4222-8222-222222222222";
const assetRef = "asset:33333333-3333-4333-8333-333333333333";
const hostRef = "host:44444444-4444-4444-8444-444444444444";
const deploymentRef = "deployment:55555555-5555-4555-8555-555555555555";
test("publishes the production ontology catalog contract", () => {
assert.equal(DEVICE_ONTOLOGY_CATALOG_HASH, "229c61c02a790906");
for (const kind of [
"asset.ensure",
"asset_binding.ensure",
"infrastructure_host.ensure",
"health_observation.record",
]) {
assert.equal(ALL_DEVICE_MANAGEMENT_COMMAND_KINDS.includes(kind), true);
}
});
test("normalizes an asset and a temporal tracker binding", () => {
const asset = normalizeDeviceManagementCommand("asset.ensure", {
projectRef,
assetKey: "trike-001",
displayName: "Trike 001",
assetTypeRef: "asset-type:delivery-trike",
});
const binding = normalizeDeviceManagementCommand("asset_binding.ensure", {
projectRef,
bindingKey: "trike-001-primary-tracker",
deviceRef,
assetRef,
bindingKind: "tracking",
validFrom: "2026-08-22T10:00:00.000Z",
provenanceRef: "onboarding:direct-b2",
});
assert.equal(asset.assetKey, "trike-001");
assert.equal(binding.deviceId, deviceRef.slice("device:".length));
assert.equal(binding.assetId, assetRef.slice("asset:".length));
assert.equal(binding.bindingKind, "tracking");
});
test("normalizes provider-neutral host topology without browser credentials", () => {
const host = normalizeOntologyManagementCommand("infrastructure_host.ensure", {
projectRef,
hostKey: "b2-edge-moscow",
displayName: "B2 Edge Moscow",
providerRef: "provider:beget",
externalRef: "provider-resource:vps-123",
managementCredentialRef: "secret-ref:device-core/b2-edge-moscow",
lifecycleState: "active",
});
const deployment = normalizeOntologyManagementCommand(
"infrastructure_deployment.ensure",
{
projectRef,
hostRef,
deploymentKey: "device-edge-001",
displayName: "Device Edge 001",
artifactRef: "artifact:device-edge/1.0.0",
artifactDigest: `sha256:${"a".repeat(64)}`,
},
);
const service = normalizeOntologyManagementCommand(
"infrastructure_service_instance.ensure",
{
projectRef,
hostRef,
deploymentRef,
serviceKey: "device-edge",
displayName: "Device Edge",
serviceRole: "device.edge",
},
);
assert.equal(host.managementCredentialRef.startsWith("secret-ref:"), true);
assert.equal(deployment.hostId, hostRef.slice("host:".length));
assert.equal(service.serviceRole, "device.edge");
assert.equal("password" in host, false);
});
test("rejects credential-bearing endpoints and secret-shaped health evidence", () => {
assert.throws(
() => normalizeOntologyManagementCommand("infrastructure_endpoint.ensure", {
projectRef,
hostRef,
endpointKey: "ssh",
purpose: "management",
endpointUri: "ssh://root:password@example.test:22/",
}),
/device_endpoint_uri_invalid/,
);
assert.throws(
() => normalizeOntologyManagementCommand("health_observation.record", {
projectRef,
subjectKind: "host",
subjectRef: hostRef,
observedState: "reachable",
evidenceClass: "management_probe",
sourceRef: "probe:device-core",
schemaRef: "schema:health.v1",
evidence: { token: "forbidden" },
observedAt: "2026-08-22T10:00:00.000Z",
expiresAt: "2026-08-22T10:01:00.000Z",
}),
/forbidden_device_field/,
);
});
test("health is a bounded observation and not a permanent online flag", () => {
const command = normalizeOntologyManagementCommand(
"health_observation.record",
{
projectRef,
subjectKind: "host",
subjectRef: hostRef,
observedState: "reachable",
evidenceClass: "management_probe",
sourceRef: "probe:device-core",
schemaRef: "schema:health.v1",
evidence: { latencyMs: 42 },
observedAt: "2026-08-22T10:00:00.000Z",
expiresAt: "2026-08-22T10:01:00.000Z",
},
);
assert.equal(command.observedState, "reachable");
assert.equal(command.expiresAt, "2026-08-22T10:01:00.000Z");
assert.throws(
() => normalizeOntologyManagementCommand("health_observation.record", {
projectRef,
subjectKind: "host",
subjectRef: hostRef,
observedState: "reachable",
evidenceClass: "management_probe",
sourceRef: "probe:device-core",
schemaRef: "schema:health.v1",
evidence: {},
observedAt: command.observedAt,
expiresAt: command.observedAt,
}),
/device_health_freshness_window_invalid/,
);
});
@@ -0,0 +1,56 @@
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import test from "node:test";
const migrationUrl = new URL(
"../migrations/016_device_asset_infrastructure_ontology.sql",
import.meta.url,
);
const repositoryUrl = new URL("../src/postgres-repository.mjs", import.meta.url);
test("ontology migration is additive and encodes the official entity identifiers", async () => {
const sql = await readFile(migrationUrl, "utf8");
for (const table of [
"device_assets",
"device_asset_bindings",
"device_infrastructure_hosts",
"device_infrastructure_deployments",
"device_infrastructure_service_instances",
"device_health_observations",
]) {
assert.match(sql, new RegExp(`create table if not exists ${table}`, "i"));
}
for (const entityId of [
"asset.asset",
"device.asset_binding",
"infrastructure.host",
"infrastructure.deployment",
"infrastructure.service_instance",
"observation.health_observation",
]) {
assert.equal(sql.includes(`'${entityId}'`), true);
}
assert.equal(sql.includes("229c61c02a790906"), true);
for (const commandKind of [
"asset.ensure",
"asset_binding.ensure",
"asset_binding.close",
"infrastructure_host.ensure",
"infrastructure_endpoint.ensure",
"infrastructure_deployment.ensure",
"infrastructure_service_instance.ensure",
"health_observation.record",
]) {
assert.equal(sql.includes(`'${commandKind}'`), true);
}
assert.doesNotMatch(sql, /insert\s+into\s+device_(?:assets|infrastructure_hosts)/i);
assert.doesNotMatch(sql, /gelios|arusnavi|beget|hetzner|aws/i);
});
test("ontology migration follows integration identity", async () => {
const source = await readFile(repositoryUrl, "utf8");
assert.ok(
source.indexOf("015_device_integration_identity.sql")
< source.indexOf("016_device_asset_infrastructure_ontology.sql"),
);
});