import assert from "node:assert/strict"; import { readFile } from "node:fs/promises"; import { L2_CONNECTION_INSTANCE_SCHEMA_VERSION, instantiateL2Connection, validateDataProductPublish, validateProviderPackage, } from "../src/index.mjs"; import { GELIOS_POSITIONS_DATA_PRODUCT_ID, GELIOS_POSITIONS_DATA_PRODUCT_VERSION, GELIOS_POSITIONS_ONTOLOGY_REVISION, GELIOS_UNIT_SOURCE_ID_PREFIX, geliosProviderPackageV1, geliosUnitsCurrentFixtureV1, } from "../providers/gelios/v1/index.mjs"; import { geliosProviderPackageV2 } from "../providers/gelios/v2/index.mjs"; import { geliosProviderPackageV3 } from "../providers/gelios/v3/index.mjs"; import { geliosProviderPackageV4 } from "../providers/gelios/v4/index.mjs"; import { geliosProviderPackageV5 } from "../providers/gelios/v5/index.mjs"; import { geliosProviderPackageV6 } from "../providers/gelios/v6/index.mjs"; import { geliosProviderPackageV7 } from "../providers/gelios/v7/index.mjs"; import { geliosProviderPackageV8 } from "../providers/gelios/v8/index.mjs"; import { normalizeDataProductDefinition } from "../../../services/external-data-plane/src/data-product-policy.mjs"; const expectedFields = [ "course_degrees", "display_name", "elevation_meters", "geometry", "hdop", "horizontal_accuracy_meters", "object_kind", "operational_status", "position_source", "position_valid", "quality_flags", "satellite_count", "speed_kph", ]; assert.deepEqual(validateProviderPackage(geliosProviderPackageV1), { ok: true, errors: [] }); assert.deepEqual(validateProviderPackage(geliosProviderPackageV2), { ok: true, errors: [] }); assert.deepEqual(validateProviderPackage(geliosProviderPackageV3), { ok: true, errors: [] }); assert.deepEqual(validateProviderPackage(geliosProviderPackageV4), { ok: true, errors: [] }); assert.deepEqual(validateProviderPackage(geliosProviderPackageV5), { ok: true, errors: [] }); assert.deepEqual(validateProviderPackage(geliosProviderPackageV6), { ok: true, errors: [] }); assert.deepEqual(validateProviderPackage(geliosProviderPackageV7), { ok: true, errors: [] }); assert.deepEqual(validateProviderPackage(geliosProviderPackageV8), { ok: true, errors: [] }); const profileProduct = geliosProviderPackageV8.dataProducts.find((product) => product.id === "fleet.units.profile.current.v1"); const registeredProfileProduct = JSON.parse(await readFile(new URL( "../../../services/external-data-plane/definitions/fleet.units.profile.current.v1.json", import.meta.url, ), "utf8")); assert.deepEqual(profileProduct, registeredProfileProduct); assert.deepEqual(profileProduct.semanticTypes, ["map.moving_object"]); assert.equal(profileProduct.history.mode, "none"); const profileCollection = geliosProviderPackageV8.collectionProfiles.find((profile) => profile.id === "gelios.units.profile.cold.v1"); assert.equal(profileCollection.schedule.intervalMs, 6 * 60 * 60 * 1000); assert.deepEqual(profileCollection.capabilityIds, ["gelios.units.current.read"]); const profileMapping = geliosProviderPackageV8.mappingContracts.find((mapping) => mapping.id === "gelios.units.to.fleet.units.profile.current.v1"); assert.equal(profileMapping.fact.sourceId.prefix, "gelios-unit-"); assert.equal(profileMapping.fact.attributes.hardware_type_name.paths[0], "hwType.name"); assert.equal(profileMapping.fact.attributes.trip_detection_type.paths[0], "tripParams.tripDetectionType.name"); assert.equal(profileMapping.fact.attributes.use_odometer.coerce, "boolean"); const telemetryProduct = geliosProviderPackageV7.dataProducts.find((product) => product.id === "fleet.positions.current.v5"); const registeredTelemetryProduct = JSON.parse(await readFile(new URL( "../../../services/external-data-plane/definitions/fleet.positions.current.v5.json", import.meta.url, ), "utf8")); assert.deepEqual(telemetryProduct, registeredTelemetryProduct); assert.equal(telemetryProduct.fieldContracts.sensor_readings.type, "telemetry_readings"); const telemetryCapability = geliosProviderPackageV7.capabilities.find((capability) => capability.id === "gelios.units.current.read"); assert.deepEqual(telemetryCapability.request.query, { incltrip: "true", inclcntrs: "true", inclsnsrs: "true", incllsv: "true", }); const telemetryMapping = geliosProviderPackageV7.mappingContracts.find((mapping) => mapping.id === "gelios.units.to.fleet.positions.current.v7"); assert.equal(telemetryMapping.derivations.sensor_readings.kind, "bounded_readings"); assert.equal(telemetryMapping.derivations.sensor_readings.parameters.maxReadings, 128); assert.equal(telemetryMapping.fact.attributes.mileage_km.paths[0], "counters.mileage.value"); assert.equal(telemetryMapping.fact.attributes.engine_hours.paths[0], "counters.engineHours.value"); assert.equal(geliosProviderPackageV7.dataProducts.some((product) => product.id === "map.gelios-geofences.current.v1"), true); const zonesProduct = geliosProviderPackageV6.dataProducts.find((product) => product.id === "map.gelios-geofences.current.v1"); const registeredZonesProduct = JSON.parse(await readFile(new URL( "../../../services/external-data-plane/definitions/map.zones.current.v2.json", import.meta.url, ), "utf8")); assert.deepEqual(zonesProduct.semanticTypes, ["map.zone"]); assert.equal(zonesProduct.fieldContracts.geometry.type, "geometry"); assert.equal(registeredZonesProduct.version, "2.0.0"); assert.deepEqual(registeredZonesProduct.fieldContracts.dataset_authority.enum, ["moscow-department-of-transport"]); assert.deepEqual(registeredZonesProduct.fieldContracts.source_adapter.enum, [ "depttrans-mmap-snapshot-v1", "depttrans-api-snapshot-v1", ]); const zonesCapability = geliosProviderPackageV6.capabilities.find((capability) => capability.id === "gelios.geozones.current.read"); assert.equal(zonesCapability.request.query.pl, 100); assert.equal(zonesCapability.request.query.po, 0); assert.equal(zonesCapability.request.response.pagination.maxItems, 5000); assert.equal(zonesCapability.request.response.pagination.totalPath, "paginationMetadata.totalCount"); const zonesMapping = geliosProviderPackageV6.mappingContracts.find((mapping) => mapping.id === "gelios.geozones.to.map.gelios-geofences.current.v1"); assert.deepEqual(zonesMapping.fact.observedAt.paths, ["updatedAt"]); assert.equal(zonesMapping.fact.observedAt.fallback, "collection_received_at"); const strictProduct = geliosProviderPackageV5.dataProducts[0]; const registeredStrictProduct = JSON.parse(await readFile(new URL( "../../../services/external-data-plane/definitions/fleet.positions.current.v4.json", import.meta.url, ), "utf8")); const geliosOntologyEntities = JSON.parse(await readFile(new URL( "../../../services/ontology-core/catalog/domain-packages/gelios/entities.json", import.meta.url, ), "utf8")); assert.equal(geliosProviderPackageV5.id, "gelios.provider.v5"); assert.equal(strictProduct.id, "fleet.positions.current.v4"); assert.deepEqual(strictProduct, registeredStrictProduct); assert.deepEqual(strictProduct.fieldContracts.signal_state.enum, ["active", "inactive"]); assert.deepEqual(strictProduct.fieldContracts.movement_state.enum, ["moving", "stopped"]); for (const ontologyEntityId of ["gelios.signal_state", "gelios.movement_state"]) { const valueContract = geliosOntologyEntities.entities.find((entity) => entity.id === ontologyEntityId)?.valueContract; assert.ok(valueContract, `${ontologyEntityId} must expose an Ontology valueContract`); assert.deepEqual( strictProduct.fieldContracts[valueContract.field].enum, valueContract.values.map(({ value: state }) => state), `${valueContract.field} Data Product enum must equal the Ontology value contract`, ); } const withInvalidClosedStateDefault = structuredClone(geliosProviderPackageV5); withInvalidClosedStateDefault.mappingContracts[0].derivations.signal_state.default = "invented"; assert.equal( validateProviderPackage(withInvalidClosedStateDefault).errors.includes( "mappingContract.gelios.units.to.fleet.positions.current.v5.fact.attributes.signal_state.derivation.default_not_in_field_contract_enum", ), true, ); const withInvalidClosedStateRule = structuredClone(geliosProviderPackageV5); withInvalidClosedStateRule.mappingContracts[0].derivations.movement_state.rules[0] = "integer_speed_gt_threshold.teleporting"; assert.equal( validateProviderPackage(withInvalidClosedStateRule).errors.includes( "mappingContract.gelios.units.to.fleet.positions.current.v5.fact.attributes.movement_state.derivation.rules[0]_not_in_field_contract_enum", ), true, ); const withOptionalRequiredState = structuredClone(geliosProviderPackageV5); withOptionalRequiredState.mappingContracts[0].fact.attributes.signal_state.omitIfMissing = true; assert.equal( validateProviderPackage(withOptionalRequiredState).errors.includes( "mappingContract.gelios.units.to.fleet.positions.current.v5.fact.attributes.signal_state_required_but_mapping_can_omit", ), true, ); const withMalformedFieldContract = structuredClone(geliosProviderPackageV5); withMalformedFieldContract.dataProducts[0].fieldContracts.signal_state = null; assert.doesNotThrow(() => validateProviderPackage(withMalformedFieldContract)); assert.equal(validateProviderPackage(withMalformedFieldContract).ok, false); const withUnboundedNumericMapping = structuredClone(geliosProviderPackageV5); delete withUnboundedNumericMapping.mappingContracts[0].fact.attributes.speed_kph.minimum; assert.equal( validateProviderPackage(withUnboundedNumericMapping).errors.includes( "mappingContract.gelios.units.to.fleet.positions.current.v5.fact.attributes.speed_kph.minimum_must_match_field_contract", ), true, ); const withNonOmittingBoundedMapping = structuredClone(geliosProviderPackageV5); withNonOmittingBoundedMapping.mappingContracts[0].fact.attributes.course_degrees.omitIfInvalid = false; assert.equal( validateProviderPackage(withNonOmittingBoundedMapping).errors.includes( "mappingContract.gelios.units.to.fleet.positions.current.v5.fact.attributes.course_degrees.bounded_number_must_omit_invalid", ), true, ); const canonicalMonitoringProduct = geliosProviderPackageV4.dataProducts[0]; const canonicalMonitoringMapping = geliosProviderPackageV4.mappingContracts[0]; const registeredCanonicalMonitoringProduct = JSON.parse(await readFile(new URL( "../../../services/external-data-plane/definitions/fleet.positions.current.v3.json", import.meta.url, ), "utf8")); assert.equal(geliosProviderPackageV4.id, "gelios.provider.v4"); assert.equal(geliosProviderPackageV4.version, "4.0.0"); assert.deepEqual(geliosProviderPackageV4.manifest.ontology, { packageId: "gelios", revision: "ontology.gelios.v1_1", }); assert.deepEqual(geliosProviderPackageV4.collectionProfiles[0].capabilityIds, [ "gelios.monitoring_config.current.read", "gelios.units.current.read", ]); assert.equal( geliosProviderPackageV4.capabilities.find((item) => item.id === "gelios.monitoring_config.current.read").request.path, "/api/v1/users/me/monitoring-config", ); assert.equal( geliosProviderPackageV4.capabilities.find((item) => item.id === "gelios.units.current.read").request.query.incltrip, "true", ); assert.deepEqual(canonicalMonitoringProduct, registeredCanonicalMonitoringProduct); assert.deepEqual(canonicalMonitoringProduct.fields.filter((field) => field.endsWith("_state")), [ "movement_state", "signal_state", ]); for (const forbiddenField of [ "availability_state", "freshness_state", "operational_status", "position_state", "state_policy_version", ]) { assert.equal(canonicalMonitoringProduct.fields.includes(forbiddenField), false); } assert.deepEqual(canonicalMonitoringMapping.derivations.signal_state.rules, [ "last_message_missing.inactive", "last_message_age_lt_resolved_monitoring_limit.active", "otherwise.inactive", ]); assert.equal(canonicalMonitoringMapping.derivations.signal_state.default, "inactive"); assert.equal(canonicalMonitoringMapping.derivations.signal_state.parameters.activeDurationPath, "signalActiveDuration"); assert.equal( canonicalMonitoringMapping.derivations.signal_state.parameters.somewhatInactiveDurationPath, "signalSomewhatInactiveDuration", ); assert.equal(canonicalMonitoringMapping.derivations.signal_state.parameters.collectionProfileFallbackSeconds, 120); assert.equal( canonicalMonitoringMapping.derivations.signal_state.parameters.thresholdResolution, "somewhatInactive_then_active_then_profileFallback", ); assert.equal(canonicalMonitoringMapping.derivations.movement_state.parameters.movingThresholdKph, 2); assert.equal(canonicalMonitoringMapping.derivations.movement_state.default, "stopped"); assert.deepEqual( geliosProviderPackageV4.l2Templates[0].steps.map((step) => step.kind), [ "collection_trigger", "provider_request", "provider_request", "extract_items", "semantic_mapping", "data_product_publish", ], ); const stateAwareProduct = geliosProviderPackageV3.dataProducts[0]; const stateAwareMapping = geliosProviderPackageV3.mappingContracts[0]; const registeredStateAwareProduct = JSON.parse(await readFile(new URL( "../../../services/external-data-plane/definitions/fleet.positions.current.v2.json", import.meta.url, ), "utf8")); assert.equal(geliosProviderPackageV3.id, "gelios.provider.v3"); assert.equal(geliosProviderPackageV3.version, "3.0.0"); assert.equal(geliosProviderPackageV3.authModes[0].id, "gelios.rest-rotating-bearer.v3"); assert.deepEqual(geliosProviderPackageV3.authModes[0].transport, { placement: "header", name: "Authorization", }); assert.deepEqual(geliosProviderPackageV3.authModes[0].tokenLifecycle, { artifacts: ["access", "refresh"], requestArtifact: "access", refreshMode: "runtime_managed", }); assert.equal(geliosProviderPackageV3.capabilities[0].request.baseUrl, "https://api.geliospro.com"); assert.equal(geliosProviderPackageV3.capabilities[0].request.path, "/api/v1/units"); assert.deepEqual(geliosProviderPackageV3.capabilities[0].request.query, {}); assert.equal( geliosProviderPackageV3.l2Templates[0].credentialBindings.find((binding) => binding.role === "provider").authModeId, "gelios.rest-rotating-bearer.v3", ); assert.equal(stateAwareProduct.id, "fleet.positions.current.v2"); assert.equal(stateAwareProduct.version, "2.0.0"); assert.equal(stateAwareProduct.ontologyRevision, "ontology.map.moving_object.v2"); assert.deepEqual(stateAwareProduct, registeredStateAwareProduct); assert.deepEqual( ["availability_state", "freshness_state", "motion_state", "position_state"].map((field) => ( stateAwareMapping.fact.attributes[field] )), [ { derive: "availability_state" }, { derive: "freshness_state" }, { derive: "motion_state" }, { derive: "position_state" }, ], ); assert.equal(stateAwareMapping.fact.attributes.state_policy_version.constant, "map-moving-object-state/v1"); assert.equal(stateAwareMapping.derivations.motion_state.parameters.movingThresholdKph, 1); assert.equal(stateAwareMapping.derivations.position_state.parameters.minSatelliteCount, 4); assert.equal(stateAwareMapping.derivations.position_state.parameters.maxHdop, 5); assert.equal(stateAwareMapping.derivations.position_state.parameters.maxHorizontalAccuracyMeters, 100); const geliosSdkAuth = geliosProviderPackageV2.authModes[0]; const geliosSdkUnitsRead = geliosProviderPackageV2.capabilities[0]; assert.equal(geliosProviderPackageV2.id, "gelios.provider.v2"); assert.equal(geliosProviderPackageV2.version, "2.0.0"); assert.equal(geliosSdkAuth.id, "gelios.sdk-query-token.v2"); assert.deepEqual(geliosSdkAuth.transport, { placement: "query", name: "token" }); assert.deepEqual(geliosSdkAuth.tokenLifecycle, { artifacts: ["access"], requestArtifact: "access", refreshMode: "not_applicable", }); assert.equal(geliosSdkUnitsRead.request.baseUrl, "https://admin.geliospro.com"); assert.equal(geliosSdkUnitsRead.request.path, "/sdk/"); assert.deepEqual(geliosSdkUnitsRead.request.query, { svc: "get_units", params: "{}" }); assert.equal(geliosProviderPackageV2.dataProducts[0].id, GELIOS_POSITIONS_DATA_PRODUCT_ID); const geliosAuth = geliosProviderPackageV1.authModes[0]; const geliosUnitsRead = geliosProviderPackageV1.capabilities[0]; assert.equal(geliosAuth.id, "gelios.rest-bearer.v1"); assert.deepEqual(geliosAuth.transport, { placement: "header", name: "Authorization" }); assert.deepEqual(geliosAuth.tokenLifecycle, { artifacts: ["access", "refresh"], requestArtifact: "access", refreshMode: "operator_managed", }); assert.equal(geliosAuth.tokenLifecycle.artifacts.includes("writer"), false); assert.equal(geliosUnitsRead.request.baseUrl, "https://api.geliospro.com"); assert.equal(geliosUnitsRead.request.path, "/api/v1/units"); assert.deepEqual(geliosUnitsRead.request.query, {}); const product = geliosProviderPackageV1.dataProducts[0]; const registeredProduct = JSON.parse(await readFile(new URL( "../../../services/external-data-plane/definitions/fleet.positions.current.v1.json", import.meta.url, ), "utf8")); assert.equal(product.id, GELIOS_POSITIONS_DATA_PRODUCT_ID); assert.equal(product.version, GELIOS_POSITIONS_DATA_PRODUCT_VERSION); assert.equal(product.ontologyRevision, GELIOS_POSITIONS_ONTOLOGY_REVISION); assert.equal(product.id, "fleet.positions.current.v1"); assert.equal(product.version, "1.0.0"); assert.equal(product.ontologyRevision, "ontology.map.moving_object.v1"); assert.deepEqual(product.fields, expectedFields); assert.deepEqual(product, registeredProduct); assert.doesNotThrow(() => normalizeDataProductDefinition(product)); assert.equal(product.fields.every((field) => /^[a-z][a-z0-9_]*$/.test(field)), true); const mapping = geliosProviderPackageV1.mappingContracts[0]; assert.equal(mapping.target.dataProductId, product.id); assert.equal(mapping.target.version, product.version); assert.equal(mapping.target.ontologyRevision, product.ontologyRevision); assert.deepEqual( [...Object.keys(mapping.fact.attributes), "geometry"].sort(), [...product.fields].sort(), ); assert.equal(mapping.derivations.operational_status.parameters.staleAfterMs, 60000); assert.deepEqual(mapping.derivations.quality_flags.default, []); assert.equal(mapping.fact.observedAt.fallback, "collection_received_at"); assert.equal(GELIOS_UNIT_SOURCE_ID_PREFIX, "gelios-unit-"); assert.equal(mapping.fact.sourceId.prefix, GELIOS_UNIT_SOURCE_ID_PREFIX); assert.equal(mapping.fact.sourceId.coerce, "string"); assert.equal(mapping.fact.geometry.longitude.paths.includes("lastMsg.lon"), true); assert.equal(mapping.fact.geometry.latitude.paths.includes("lastMsg.lat"), true); assert.equal(mapping.fact.attributes.speed_kph.paths.includes("lastMsg.speed"), true); assert.equal(validateDataProductPublish(geliosUnitsCurrentFixtureV1.expectedPublish).ok, true); assert.equal( geliosUnitsCurrentFixtureV1.sourceResponse.units.length, geliosUnitsCurrentFixtureV1.expectedPublish.facts.length, "every entity returned for the bound credential remains in the publish fixture", ); assert.deepEqual( geliosUnitsCurrentFixtureV1.expectedPublish.facts.map((fact) => fact.sourceId), geliosUnitsCurrentFixtureV1.sourceResponse.units.map( (unit) => `${GELIOS_UNIT_SOURCE_ID_PREFIX}${String(unit.id)}`, ), ); assert.equal( geliosUnitsCurrentFixtureV1.expectedPublish.facts[1].sourceId, "gelios-unit-001002", "provider ID strings must remain byte-for-byte stable after the canonical prefix", ); assert.equal(geliosUnitsCurrentFixtureV1.expectedPublish.facts[1].geometry, undefined); assert.equal(geliosUnitsCurrentFixtureV1.expectedPublish.facts[1].attributes.operational_status, "no_position"); assert.equal(geliosUnitsCurrentFixtureV1.sourceResponse.units[1].lastMsg, undefined); assert.equal( geliosUnitsCurrentFixtureV1.expectedPublish.facts[1].observedAt, geliosUnitsCurrentFixtureV1.collectionContext.receivedAt, ); const realtimeProfileId = "gelios.positions.current.realtime.v1"; assert.equal( geliosProviderPackageV1.collectionProfiles[0].cardinality.onExceed, "require_partitioned_data_product", ); const accountA = instantiateL2Connection(geliosProviderPackageV1, { tenantId: "tenant-alpha", connectionId: "gelios-account-alpha", collectionProfileId: realtimeProfileId, providerCredentialRef: "ndc-credref:provider-alpha-0001", }); const accountB = instantiateL2Connection(geliosProviderPackageV1, { tenantId: "tenant-beta", connectionId: "gelios-account-beta", collectionProfileId: realtimeProfileId, providerCredentialRef: "ndc-credref:provider-beta-0001", }); assert.equal(accountA.schemaVersion, L2_CONNECTION_INSTANCE_SCHEMA_VERSION); assert.equal(accountA.package.id, accountB.package.id); assert.equal(accountA.package.version, accountB.package.version); assert.equal(accountA.l2TemplateId, accountB.l2TemplateId); assert.notEqual(accountA.connectionId, accountB.connectionId); assert.notEqual(accountA.credentialRefs.provider.reference, accountB.credentialRefs.provider.reference); assert.equal(accountA.credentialRefs.provider.owner, "ndc_l2_credentials"); assert.deepEqual(Object.keys(accountA.credentialRefs), ["provider"]); assert.deepEqual(accountA.systemBindings.publisher, { role: "publisher", owner: "ndc_l2_credentials", management: "control_plane_managed", nodeType: "n8n-nodes-ndc.ndcDataProductPublish", desiredState: "bound", status: "unresolved", }); assert.equal(accountA.scope.mode, "all_visible_to_credential"); assert.equal(accountA.scope.refresh, "each_collection_run"); assert.equal(Object.isFrozen(accountA), true); assert.equal(Object.isFrozen(accountA.credentialRefs), true); assert.equal(Object.isFrozen(accountA.systemBindings), true); const withEntityAllowlist = structuredClone(geliosProviderPackageV1); withEntityAllowlist.capabilities[0].entityScope.unitIds = ["gelios-unit-1001"]; assert.equal( validateProviderPackage(withEntityAllowlist).errors.includes("capabilities[0].entityScope.unitIds_not_allowed"), true, ); const withGroupFilter = structuredClone(geliosProviderPackageV1); withGroupFilter.collectionProfiles[0].entityScope.businessEntityFilter = "provider_group"; assert.equal( validateProviderPackage(withGroupFilter).errors.includes("collectionProfiles[0].entityScope.businessEntityFilter_must_be_forbidden"), true, ); const withWrongRevision = structuredClone(geliosProviderPackageV1); withWrongRevision.mappingContracts[0].target.ontologyRevision = "gelios.positions.v1"; assert.equal( validateProviderPackage(withWrongRevision).errors.includes("mappingContract.gelios.units.to.fleet.positions.current.v1.target.ontologyRevision_must_match_data_product"), true, ); const withMissingDerivation = structuredClone(geliosProviderPackageV1); delete withMissingDerivation.mappingContracts[0].derivations.position_valid; assert.equal( validateProviderPackage(withMissingDerivation).errors.includes("mappingContracts[0].derive_position_valid_missing_definition"), true, ); const withWrongFactSemanticType = structuredClone(geliosProviderPackageV1); withWrongFactSemanticType.mappingContracts[0].fact.semanticType.constant = "map.other"; assert.equal( validateProviderPackage(withWrongFactSemanticType).errors.includes( "mappingContract.gelios.units.to.fleet.positions.current.v1.fact.semanticType_must_equal_target_constant", ), true, ); const nonGeospatialPackage = structuredClone(geliosProviderPackageV1); nonGeospatialPackage.dataProducts[0].fields = ["display_name"]; nonGeospatialPackage.fieldPolicies[0].targetFields = ["display_name"]; delete nonGeospatialPackage.mappingContracts[0].fact.geometry; nonGeospatialPackage.mappingContracts[0].fact.attributes = { display_name: { strategy: "first_non_empty", paths: ["name"], coerce: "string" }, }; delete nonGeospatialPackage.mappingContracts[0].derivations; assert.deepEqual(validateProviderPackage(nonGeospatialPackage), { ok: true, errors: [] }); for (const restrictedPath of ["phone", "phone.number", "lmsg"]) { const withRestrictedMappingPath = structuredClone(geliosProviderPackageV1); withRestrictedMappingPath.mappingContracts[0].fact.attributes.display_name.paths = [restrictedPath]; assert.equal( validateProviderPackage(withRestrictedMappingPath).errors.includes( "mappingContract.gelios.units.to.fleet.positions.current.v1.fact_source_path_restricted", ), true, ); } const withFieldPolicyProductMismatch = structuredClone(geliosProviderPackageV1); const secondProduct = structuredClone(withFieldPolicyProductMismatch.dataProducts[0]); secondProduct.id = "fleet.positions.alternate.v1"; withFieldPolicyProductMismatch.dataProducts.push(secondProduct); withFieldPolicyProductMismatch.manifest.dataProductIds.push(secondProduct.id); withFieldPolicyProductMismatch.fieldPolicies[0].dataProductId = secondProduct.id; assert.equal( validateProviderPackage(withFieldPolicyProductMismatch).errors.includes( "mappingContract.gelios.units.to.fleet.positions.current.v1.field_policy_data_product_mismatch", ), true, ); const withCamelCaseField = structuredClone(geliosProviderPackageV1); withCamelCaseField.dataProducts[0].fields[12] = "speedKph"; assert.equal(validateProviderPackage(withCamelCaseField).ok, false); const withSecretField = structuredClone(geliosProviderPackageV1); withSecretField.dataProducts[0].fields[12] = "api_token"; withSecretField.fieldPolicies[0].targetFields[12] = "api_token"; withSecretField.mappingContracts[0].fact.attributes.api_token = { constant: "metadata-only" }; delete withSecretField.mappingContracts[0].fact.attributes.speed_kph; const secretFieldValidation = validateProviderPackage(withSecretField); assert.equal(secretFieldValidation.errors.includes("dataProducts[0].fields_must_not_contain_secret_fields"), true); assert.equal(secretFieldValidation.errors.includes("fieldPolicies[0].targetFields_must_not_contain_secret_fields"), true); assert.equal(secretFieldValidation.errors.includes("mappingContracts[0].fact.attributes.api_token_secret_field_not_allowed"), true); const withRuntimeAccountState = structuredClone(geliosProviderPackageV1); withRuntimeAccountState.tenantId = "must-not-live-in-package"; assert.equal( validateProviderPackage(withRuntimeAccountState).errors.includes("providerPackage_must_not_contain_connection_instance_state"), true, ); const withPrimitiveCapability = structuredClone(geliosProviderPackageV1); withPrimitiveCapability.capabilities.push(null); assert.doesNotThrow(() => validateProviderPackage(withPrimitiveCapability)); assert.equal(validateProviderPackage(withPrimitiveCapability).ok, false); const withMalformedNestedArrays = structuredClone(geliosProviderPackageV1); withMalformedNestedArrays.collectionProfiles[0].capabilityIds = {}; withMalformedNestedArrays.l2Templates[0].credentialBindings = {}; withMalformedNestedArrays.l2Templates[0].steps = {}; assert.doesNotThrow(() => validateProviderPackage(withMalformedNestedArrays)); assert.equal(validateProviderPackage(withMalformedNestedArrays).ok, false); const withCredentialInStaticQuery = structuredClone(geliosProviderPackageV1); withCredentialInStaticQuery.authModes[0].transport = { placement: "query", name: "token" }; withCredentialInStaticQuery.capabilities[0].request.query.token = "plain-provider-key"; assert.equal( validateProviderPackage(withCredentialInStaticQuery).errors.includes("capabilities[0].request.query.token_credential_parameter_not_allowed"), true, ); assert.equal( validateProviderPackage(withCredentialInStaticQuery).errors.includes("capability.gelios.units.current.read.request.query_must_not_embed_credential_parameter"), true, ); const withCredentialInBaseUrl = structuredClone(geliosProviderPackageV1); withCredentialInBaseUrl.capabilities[0].request.baseUrl = "https://user:pass@api.geliospro.com/?token=forbidden"; assert.equal(validateProviderPackage(withCredentialInBaseUrl).ok, false); for (const unsafePath of ["/ok\nX-Evil: yes", "/back\\slash", "/query?x=1"]) { const withUnsafeRequestPath = structuredClone(geliosProviderPackageV1); withUnsafeRequestPath.capabilities[0].request.path = unsafePath; assert.equal(validateProviderPackage(withUnsafeRequestPath).ok, false); } for (const unsafeCollectionPath of ["__proto__.polluted", "data.items[0]", "constructor.prototype"]) { const withUnsafeCollectionPath = structuredClone(geliosProviderPackageV1); withUnsafeCollectionPath.capabilities[0].request.response.collectionPaths = [unsafeCollectionPath]; assert.equal(validateProviderPackage(withUnsafeCollectionPath).ok, false); } const withUnsafeMappingPath = structuredClone(geliosProviderPackageV1); withUnsafeMappingPath.mappingContracts[0].fact.attributes.display_name.paths = ["__proto__.polluted"]; assert.equal(validateProviderPackage(withUnsafeMappingPath).ok, false); const withUnsafeCollectionCapability = structuredClone(geliosProviderPackageV1); withUnsafeCollectionCapability.capabilities[0].classification = "write"; assert.equal( validateProviderPackage(withUnsafeCollectionCapability).errors.includes("collectionProfile.gelios.positions.current.realtime.v1.capabilityIds_must_reference_implemented_safe_read"), true, ); const withUnexecutedSecondCapability = structuredClone(geliosProviderPackageV1); const secondCapability = structuredClone(withUnexecutedSecondCapability.capabilities[0]); secondCapability.id = "gelios.units.metadata.read"; withUnexecutedSecondCapability.capabilities.push(secondCapability); withUnexecutedSecondCapability.manifest.capabilityIds.push(secondCapability.id); for (const profile of withUnexecutedSecondCapability.collectionProfiles) { profile.capabilityIds.push(secondCapability.id); } assert.equal( validateProviderPackage(withUnexecutedSecondCapability).errors.includes( "collectionProfile.gelios.positions.current.realtime.v1.template_capability_chain_mismatch", ), true, ); const withReorderedSteps = structuredClone(geliosProviderPackageV1); [withReorderedSteps.l2Templates[0].steps[0], withReorderedSteps.l2Templates[0].steps[1]] = [ withReorderedSteps.l2Templates[0].steps[1], withReorderedSteps.l2Templates[0].steps[0], ]; assert.equal( validateProviderPackage(withReorderedSteps).errors.includes("l2Templates[0].steps_sequence_invalid"), true, ); const withUnknownConnectionParameters = structuredClone(geliosProviderPackageV1); withUnknownConnectionParameters.l2Templates[0].connectionParameters = ["foo"]; assert.equal( validateProviderPackage(withUnknownConnectionParameters).errors.includes( "l2Templates[0].connectionParameters_must_match_v1_contract", ), true, ); const withCredentialAuthMismatch = structuredClone(geliosProviderPackageV1); const secondAuthMode = structuredClone(withCredentialAuthMismatch.authModes[0]); secondAuthMode.id = "gelios.rest-bearer.alternate.v1"; withCredentialAuthMismatch.authModes.push(secondAuthMode); withCredentialAuthMismatch.manifest.authModeIds.push(secondAuthMode.id); withCredentialAuthMismatch.l2Templates[0].credentialBindings[0].authModeId = secondAuthMode.id; assert.equal( validateProviderPackage(withCredentialAuthMismatch).errors.includes( "l2Template.gelios.positions.current.l2.v1.provider_credential_auth_mode_mismatch", ), true, ); const withCallerManagedPublisher = structuredClone(geliosProviderPackageV1); withCallerManagedPublisher.l2Templates[0].credentialBindings[1].management = "connection_input"; assert.equal( validateProviderPackage(withCallerManagedPublisher).errors.includes( "l2Templates[0].credentialBindings[1].publisher_binding_shape_invalid", ), true, ); const withUnknownTokenArtifact = structuredClone(geliosProviderPackageV1); withUnknownTokenArtifact.authModes[0].tokenLifecycle.artifacts.push("writer"); assert.equal( validateProviderPackage(withUnknownTokenArtifact).errors.includes( "authModes[0].tokenLifecycle.artifacts_invalid", ), true, ); const withRefreshUsedForRequest = structuredClone(geliosProviderPackageV1); withRefreshUsedForRequest.authModes[0].tokenLifecycle.requestArtifact = "refresh"; assert.equal( validateProviderPackage(withRefreshUsedForRequest).errors.includes( "authModes[0].tokenLifecycle.requestArtifact_must_be_access", ), true, ); const withUnmanagedRefreshArtifact = structuredClone(geliosProviderPackageV1); withUnmanagedRefreshArtifact.authModes[0].tokenLifecycle.refreshMode = "not_applicable"; assert.equal( validateProviderPackage(withUnmanagedRefreshArtifact).errors.includes( "authModes[0].tokenLifecycle.refreshMode_required_for_refresh_artifact", ), true, ); for (const history of [{ mode: "none", intervalMs: 60000, strategy: "latest-per-entity-per-bucket", retentionDays: 90, }, { mode: "sampled", intervalMs: 24 * 60 * 60 * 1000 + 1, strategy: "latest-per-entity-per-bucket", retentionDays: 90, }, { mode: "all", retentionDays: 3651, }]) { const withInvalidHistory = structuredClone(geliosProviderPackageV1); withInvalidHistory.dataProducts[0].history = history; assert.equal(validateProviderPackage(withInvalidHistory).ok, false); assert.throws(() => normalizeDataProductDefinition(withInvalidHistory.dataProducts[0])); } const withBrokenArtifactChain = structuredClone(geliosProviderPackageV1); withBrokenArtifactChain.l2Templates[0].steps[4].dataProductId = "unrelated.product.v1"; assert.equal( validateProviderPackage(withBrokenArtifactChain).errors.includes("collectionProfile.gelios.positions.current.realtime.v1.template_data_product_mismatch"), true, ); const withSecretNamedDerivationParameter = structuredClone(geliosProviderPackageV1); withSecretNamedDerivationParameter.mappingContracts[0].derivations.position_valid.parameters = { accessToken: "opaque-provider-value", }; assert.equal( validateProviderPackage(withSecretNamedDerivationParameter).errors.includes( "mappingContracts[0].derivations.position_valid.parameters.accessToken_secret_field_not_allowed", ), true, ); const withObjectConstant = structuredClone(geliosProviderPackageV1); withObjectConstant.mappingContracts[0].fact.attributes.object_kind.constant = { accessToken: "opaque-provider-value", }; assert.equal( validateProviderPackage(withObjectConstant).errors.includes( "mappingContracts[0].fact.attributes.object_kind.constant_must_be_scalar_or_scalar_array", ), true, ); assert.throws(() => instantiateL2Connection(geliosProviderPackageV1, { tenantId: "tenant-alpha", connectionId: "gelios-account-alpha", collectionProfileId: realtimeProfileId, providerCredentialRef: "Bearer plaintext-must-not-cross-boundary", }), /l2_connection_invalid/); assert.throws(() => instantiateL2Connection(geliosProviderPackageV1, { tenantId: "tenant-alpha", connectionId: "gelios-account-alpha", collectionProfileId: realtimeProfileId, providerCredentialRef: "ndc-credref:provider-alpha-0001", writerCredentialRef: "ndc-credref:caller-writer-forbidden", }), /options\.writerCredentialRef_not_allowed/); const serializedPackage = JSON.stringify(geliosProviderPackageV1); assert.equal(serializedPackage.includes('"prefix":"unit-"'), false); assert.equal(serializedPackage.includes("unitIds"), false); assert.equal(serializedPackage.includes("tenant-alpha"), false); assert.equal(serializedPackage.includes("gelios-gateway"), false); assert.equal(serializedPackage.includes("writer_credential_ref"), false); assert.equal(serializedPackage.includes("writerCapabilityByReferenceOnly"), false); assert.equal(serializedPackage.includes("publisherBindingControlPlaneManaged\":true"), true); assert.equal(serializedPackage.includes("providerSpecificServiceForbidden\":true"), true); assert.deepEqual( geliosProviderPackageV1.l2Templates[0].steps.map((step) => step.kind), [ "collection_trigger", "provider_request", "extract_items", "semantic_mapping", "data_product_publish", ], ); assert.equal( geliosProviderPackageV1.l2Templates[0].steps.at(-1).nodeType, "n8n-nodes-ndc.ndcDataProductPublish", ); console.log("external-provider-contract provider-package: ok");