NODEDC_PLATFORM/infra/deploy-runner/generate-engine-gelios-v11-...

182 lines
6.2 KiB
JavaScript

#!/usr/bin/env node
import { createHash } from "node:crypto";
import { readFile, writeFile } from "node:fs/promises";
import { resolve } from "node:path";
import {
compileL2ExecutionPlan,
instantiateL2Connection,
} from "../../packages/external-provider-contract/src/index.mjs";
import {
geliosProviderPackageV11,
geliosTelemetryFieldRegistryV4,
} from "../../packages/external-provider-contract/providers/gelios/v11/index.mjs";
const engineRoot = resolve(
process.env.NODEDC_ENGINE_SOURCE_ROOT || "../NODEDC_ENGINE_INFRA",
);
const executionCatalogPath = resolve(
engineRoot,
"nodedc-source/server/assets/execution-plans/v1/catalog.json",
);
const securityCatalogPath = resolve(
engineRoot,
"nodedc-source/server/assets/provider-packages/v1/catalog.json",
);
const executionCatalog = JSON.parse(
await readFile(executionCatalogPath, "utf8"),
);
executionCatalog.runtime.compilerVersions = [
...new Set([...executionCatalog.runtime.compilerVersions, "1.4.0"]),
].sort();
executionCatalog.runtime.derivationKinds = [
...new Set([
...executionCatalog.runtime.derivationKinds,
"bounded_named_values",
"bounded_string_list",
]),
].sort();
executionCatalog.runtime.ruleIds = [
...new Set([
...executionCatalog.runtime.ruleIds,
"array.named_values",
"array.string_values",
]),
].sort();
executionCatalog.packages = executionCatalog.packages.filter(
(providerPackage) => providerPackage.id !== geliosProviderPackageV11.id,
);
executionCatalog.packages.push(executionCatalogEntry());
await writeFile(executionCatalogPath, `${JSON.stringify(executionCatalog, null, 2)}\n`);
const securityCatalog = JSON.parse(
await readFile(securityCatalogPath, "utf8"),
);
securityCatalog.packages = securityCatalog.packages.filter(
(providerPackage) => providerPackage.id !== geliosProviderPackageV11.id,
);
securityCatalog.packages.push(securityCatalogEntry());
await writeFile(securityCatalogPath, `${JSON.stringify(securityCatalog, null, 2)}\n`);
console.log(JSON.stringify({
ok: true,
providerPackage: geliosProviderPackageV11.id,
executionCatalogPath,
securityCatalogPath,
}, null, 2));
function executionCatalogEntry() {
const profiles = geliosProviderPackageV11.collectionProfiles.map((profile) => {
const connection = instantiateL2Connection(geliosProviderPackageV11, {
tenantId: "tenant-catalog-build",
connectionId: `catalog-${profile.id.replaceAll(".", "-")}`,
collectionProfileId: profile.id,
providerCredentialRef: "ndc-credref:catalog-build-provider-v11",
});
const plan = compileL2ExecutionPlan(
geliosProviderPackageV11,
connection,
profile.dataProductId === "fleet.positions.current.v5"
? { telemetryFieldRegistry: geliosTelemetryFieldRegistryV4 }
: {},
);
const { packageDigest: _packageDigest, ...artifacts } = plan.artifacts;
return {
id: profile.id,
dataProductId: profile.dataProductId,
capabilityIds: [...profile.capabilityIds],
stepSignatures: plan.steps.map((step) => ({
id: step.id,
kind: step.kind,
...(step.config.capabilityId ? { capabilityId: step.config.capabilityId } : {}),
...(step.config.mappingContractId ? {
mappingContractId: step.config.mappingContractId,
} : {}),
...(step.config.dataProductId ? { dataProductId: step.config.dataProductId } : {}),
...(step.config.nodeType ? { nodeType: step.config.nodeType } : {}),
})),
artifacts,
};
});
return {
id: geliosProviderPackageV11.id,
providerId: geliosProviderPackageV11.providerId,
version: geliosProviderPackageV11.version,
contractDigest: canonicalDigest(geliosProviderPackageV11),
providerCredential: {
authModeId: "gelios.rest-rotating-bearer.v3",
credentialType: "ndcProviderRotatingAccessApi",
},
publisher: {
nodeType: "n8n-nodes-ndc.ndcDataProductPublish",
credentialType: "ndcDataProductWriterApi",
},
capabilities: geliosProviderPackageV11.capabilities.map((capability) => ({
id: capability.id,
contractDigest: canonicalDigest(capability),
requestDigest: canonicalDigest(capability.request),
method: capability.request.method,
url: requestUrl(capability.request),
})),
profiles,
};
}
function securityCatalogEntry() {
const productsByCapability = new Map(
geliosProviderPackageV11.capabilities.map((capability) => [capability.id, new Set()]),
);
for (const profile of geliosProviderPackageV11.collectionProfiles) {
if (profile.dataProductId !== "fleet.units.identity.current.v1") continue;
for (const capabilityId of profile.capabilityIds) {
productsByCapability.get(capabilityId)?.add(profile.dataProductId);
}
}
return {
id: geliosProviderPackageV11.id,
version: geliosProviderPackageV11.version,
providerId: geliosProviderPackageV11.providerId,
providerCredential: {
authModeId: "gelios.rest-rotating-bearer.v3",
credentialType: "ndcProviderRotatingAccessApi",
},
capabilities: geliosProviderPackageV11.capabilities
.filter((capability) => productsByCapability.get(capability.id)?.size)
.map((capability) => ({
id: capability.id,
classification: capability.classification,
status: capability.status,
request: {
method: capability.request.method,
url: requestUrl(capability.request),
},
dataProductIds: [...productsByCapability.get(capability.id)].sort(),
})),
publisher: {
nodeType: "n8n-nodes-ndc.ndcDataProductPublish",
credentialType: "ndcDataProductWriterApi",
},
};
}
function requestUrl(request) {
const url = new URL(request.path, request.baseUrl);
for (const [name, value] of Object.entries(request.query || {})) {
url.searchParams.append(name, String(value));
}
return url.toString();
}
function canonicalDigest(value) {
return `sha256:${createHash("sha256").update(JSON.stringify(stableValue(value)), "utf8").digest("hex")}`;
}
function stableValue(value) {
if (Array.isArray(value)) return value.map(stableValue);
if (!value || typeof value !== "object") return value;
return Object.fromEntries(
Object.keys(value).sort().map((key) => [key, stableValue(value[key])]),
);
}