#!/usr/bin/env node import assert from "node:assert/strict"; import { readdir, readFile } from "node:fs/promises"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { ENVIRONMENT_DEV, SERVICE_IDS, TABLES, validateRequest, validateResponse } from "../internal/protocol/index.mjs"; const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); async function parseJSONFiles(dir, { requireSchema = true } = {}) { const entries = await readdir(path.join(repoRoot, dir), { withFileTypes: true }); const parsed = []; for (const entry of entries) { if (!entry.isFile() || !entry.name.endsWith(".json")) { continue; } const relativePath = path.join(dir, entry.name); const raw = await readFile(path.join(repoRoot, relativePath), "utf8"); const doc = JSON.parse(raw); if (requireSchema) { assert.ok(doc.$schema, `${relativePath} missing $schema`); assert.ok(doc.$id, `${relativePath} missing $id`); } parsed.push({ relativePath, doc }); } return parsed; } async function parseJSONSchemaFiles(dir) { const parsed = []; for (const item of await parseJSONFiles(dir, { requireSchema: false })) { if (!item.doc.$schema || !item.doc.$id) { continue; } parsed.push(item); } return parsed; } async function parseDeployManifest(relativePath) { const raw = await readFile(path.join(repoRoot, relativePath), "utf8"); const doc = JSON.parse(raw); assert.equal(doc.manifestVersion, "v1", `${relativePath} manifestVersion`); assert.equal(doc.environment, ENVIRONMENT_DEV, `${relativePath} environment`); assert.ok(doc.commitId, `${relativePath} commitId`); assert.ok(Array.isArray(doc.services) && doc.services.length >= 1, `${relativePath} services`); return doc; } function assertUnique(name, values) { assert.equal(new Set(values).size, values.length, `${name} must be unique`); } function assertCommonSchema(commonSchema) { const schemaServiceIds = commonSchema.$defs.serviceId.enum; assert.deepEqual(schemaServiceIds, SERVICE_IDS, "common service ids must match runtime constants"); assert.deepEqual(commonSchema.$defs.environment.enum, [ENVIRONMENT_DEV]); } function assertDeploySchema(deploySchema) { const serviceIds = deploySchema.$defs.service.properties.serviceId.enum; assert.deepEqual(serviceIds, SERVICE_IDS, "deploy service ids must match runtime constants"); assert.equal(deploySchema.properties.endpoint.const, "http://74.48.78.17:16667"); } function assertEnvelopeValidation() { validateRequest({ jsonrpc: "2.0", id: "req_01J00000000000000000000000", method: "hardware.operation.request", params: { projectId: "prj_01J00000000000000000000000" }, meta: { traceId: "trc_01J00000000000000000000000", serviceId: "hwlab-cloud-api", environment: "dev" } }); validateResponse({ jsonrpc: "2.0", id: "req_01J00000000000000000000000", result: { accepted: true }, meta: { traceId: "trc_01J00000000000000000000000", serviceId: "hwlab-agent-mgr", environment: "dev" } }); assert.throws( () => validateResponse({ jsonrpc: "2.0", id: "req_01J00000000000000000000000", result: {}, error: { code: -32000, message: "bad" }, meta: { traceId: "trc_01J00000000000000000000000", serviceId: "hwlab-agent-mgr", environment: "dev" } }), /exactly one/ ); } const schemas = await parseJSONSchemaFiles("protocol/schemas"); const deploySchemas = await parseJSONSchemaFiles("deploy"); const deployManifest = await parseDeployManifest("deploy/deploy.json"); const docsByName = new Map([...schemas, ...deploySchemas].map((item) => [path.basename(item.relativePath), item.doc])); assert.ok(schemas.length >= 13, "expected protocol schemas"); assert.ok(TABLES.includes("patch_panel_status"), "frozen tables must include patch_panel_status"); assertUnique("service ids", SERVICE_IDS); assertUnique("tables", TABLES); assertCommonSchema(docsByName.get("common.json")); assertDeploySchema(docsByName.get("deploy.schema.json")); assertEnvelopeValidation(); const deployServicesById = new Map(deployManifest.services.map((service) => [service.serviceId, service])); assert.equal(deployServicesById.has("hwlab-agent-mgr"), true); assert.equal(deployServicesById.has("hwlab-agent-worker"), true); assert.equal(deployServicesById.has("hwlab-agent-skills"), true); const cloudApi = deployServicesById.get("hwlab-cloud-api"); assert.equal(cloudApi.healthPath, "/health/live", "cloud-api health path"); assert.equal(cloudApi.env.HWLAB_COMMIT_ID, deployManifest.commitId, "cloud-api health commit evidence"); assert.equal(cloudApi.env.HWLAB_IMAGE, cloudApi.image, "cloud-api health image evidence"); assert.equal(cloudApi.env.HWLAB_IMAGE_TAG, deployManifest.commitId.slice(0, 7), "cloud-api health image tag evidence"); assert.equal(cloudApi.env.HWLAB_CLOUD_DB_URL, "secretRef:hwlab-cloud-api-dev-db/database-url", "cloud-api DB URL must be a Secret reference placeholder"); assert.equal(cloudApi.env.HWLAB_CLOUD_DB_SSL_MODE, "require", "cloud-api DB SSL mode"); assert.equal(cloudApi.env.HWLAB_CLOUD_DB_CONTRACT, "dev-redacted-presence-only", "cloud-api DB contract marker"); console.log(`validated ${schemas.length + deploySchemas.length} JSON files and ${SERVICE_IDS.length} service ids`);