import assert from "node:assert/strict"; import { ENGINE_PRIVATE_EXTENSION_APPLY_RECEIPT_SCHEMA_VERSION, ENGINE_PRIVATE_EXTENSION_APPLY_REQUEST_SCHEMA_VERSION, ENGINE_PRIVATE_EXTENSION_CREDENTIAL_TYPES, ENGINE_PRIVATE_EXTENSION_INACTIVE_BASELINE, ENGINE_PRIVATE_EXTENSION_MANAGE_CAPABILITY, ENGINE_PRIVATE_EXTENSION_NODE_TYPES, ENGINE_PRIVATE_EXTENSION_OPERATION_SCHEMA_VERSION, ENGINE_PRIVATE_EXTENSION_PACKAGE_NAME, ENGINE_PRIVATE_EXTENSION_PLAN_REQUEST_SCHEMA_VERSION, ENGINE_PRIVATE_EXTENSION_PLAN_SCHEMA_VERSION, ENGINE_PRIVATE_EXTENSION_READ_CAPABILITY, ENGINE_PRIVATE_EXTENSION_STATUS_SCHEMA_VERSION, authorizeEnginePrivateExtensionOperation, computeEnginePrivateExtensionPlanHash, validateEnginePrivateExtensionApplyReceipt, validateEnginePrivateExtensionApplyRequest, validateEnginePrivateExtensionOperation, validateEnginePrivateExtensionPlan, validateEnginePrivateExtensionPlanRequest, validateEnginePrivateExtensionStatus, } from "../src/index.mjs"; const digest = "03413c6f3c706a1f6a9597a1cf1730504e9719228d0c77fdfb93bbdcc57a4cf3"; const release = Object.freeze({ kind: "release", packageName: ENGINE_PRIVATE_EXTENSION_PACKAGE_NAME, releaseId: "0.1.0-03413c6f3c706a1f", packageSha256: digest, }); const inactive = Object.freeze({ kind: "inactive-baseline", packageName: ENGINE_PRIVATE_EXTENSION_PACKAGE_NAME, baselineId: ENGINE_PRIVATE_EXTENSION_INACTIVE_BASELINE, }); const manage = [ENGINE_PRIVATE_EXTENSION_MANAGE_CAPABILITY]; const activateRequest = { schemaVersion: ENGINE_PRIVATE_EXTENSION_PLAN_REQUEST_SCHEMA_VERSION, requestId: "extension-request-20260715-001", idempotencyKey: "extension-request-20260715-001", action: "activate", requestedAt: "2026-07-15T18:00:00.000Z", requestExpiresAt: "2026-07-15T18:10:00.000Z", expectedCurrentGeneration: 0, target: release, }; assert.deepEqual( validateEnginePrivateExtensionPlanRequest(activateRequest, { now: "2026-07-15T18:00:01.000Z", grantedCapabilities: manage, }), { ok: true, errors: [] }, ); assert.equal( validateEnginePrivateExtensionPlanRequest(activateRequest, { now: "2026-07-15T18:00:01.000Z", grantedCapabilities: ["engine.l2.deploy"], }).errors.includes("engine_private_extension_capability_required"), true, ); assert.equal(authorizeEnginePrivateExtensionOperation("status", [ENGINE_PRIVATE_EXTENSION_READ_CAPABILITY]).ok, true); assert.equal(authorizeEnginePrivateExtensionOperation("apply", [ENGINE_PRIVATE_EXTENSION_READ_CAPABILITY]).ok, false); const activatePlan = withPlanHash({ schemaVersion: ENGINE_PRIVATE_EXTENSION_PLAN_SCHEMA_VERSION, planId: "extension-plan-20260715-001", planHash: hash("0"), requestId: activateRequest.requestId, idempotencyKey: activateRequest.idempotencyKey, action: "activate", createdAt: "2026-07-15T18:00:01.000Z", expiresAt: "2026-07-15T18:09:00.000Z", singleUse: true, requiredCapability: ENGINE_PRIVATE_EXTENSION_MANAGE_CAPABILITY, expectedCurrentGeneration: 0, nextGeneration: 1, currentState: inactive, targetState: release, recoveryState: inactive, actions: [ "verify_staged_immutable_release", "prepare_sealed_package_tree", "verify_community_package_loader_policy", "quiesce_deploy_run_and_drain_queue", "record_recovery_state", "atomic_switch_current", "force_recreate_main_workers_webhooks_as_version_barrier", "verify_exact_runtime_acceptance", "commit_active_state", "resume_deploy_run", ], transition: transition(), acceptance: acceptanceSpec(release), failurePolicy: failurePolicy(), }); assert.deepEqual(validateEnginePrivateExtensionPlan(activatePlan, { request: activateRequest }), { ok: true, errors: [] }); assert.equal( validateEnginePrivateExtensionPlan({ ...activatePlan, nextGeneration: 2 }).errors.includes("nextGeneration_must_increment_current_generation"), true, ); assert.equal( validateEnginePrivateExtensionPlan({ ...activatePlan, transition: { ...transition(), runtimeAction: "restart" } }) .errors.includes("transition_policy_mismatch"), true, ); assert.equal( validateEnginePrivateExtensionPlan({ ...activatePlan, transition: { ...transition(), loaderMode: "custom-extension", loaderPath: "N8N_CUSTOM_EXTENSIONS" }, }).errors.includes("transition_policy_mismatch"), true, ); assert.equal( validateEnginePrivateExtensionPlan({ ...activatePlan, transition: { ...transition(), hotReload: true }, }).errors.includes("transition_policy_mismatch"), true, ); assert.equal( validateEnginePrivateExtensionPlan({ ...activatePlan, transition: { ...transition(), loaderEnvironment: { ...transition().loaderEnvironment, N8N_REINSTALL_MISSING_PACKAGES: "true" }, }, }).errors.includes("transition_policy_mismatch"), true, ); const applyRequest = { schemaVersion: ENGINE_PRIVATE_EXTENSION_APPLY_REQUEST_SCHEMA_VERSION, planId: activatePlan.planId, planHash: activatePlan.planHash, idempotencyKey: activatePlan.idempotencyKey, confirmedAt: "2026-07-15T18:00:02.000Z", }; assert.deepEqual(validateEnginePrivateExtensionApplyRequest(applyRequest, { plan: activatePlan, now: "2026-07-15T18:00:02.000Z", grantedCapabilities: manage, }), { ok: true, errors: [] }); assert.equal(validateEnginePrivateExtensionApplyRequest(applyRequest, { plan: activatePlan, now: "2026-07-15T18:10:00.000Z", grantedCapabilities: manage, }).errors.includes("plan_expired"), true); const receipt = { schemaVersion: ENGINE_PRIVATE_EXTENSION_APPLY_RECEIPT_SCHEMA_VERSION, operationId: "extension-operation-20260715-001", planId: activatePlan.planId, planHash: activatePlan.planHash, action: "activate", acceptedAt: "2026-07-15T18:00:02.100Z", state: "queued", }; assert.deepEqual(validateEnginePrivateExtensionApplyReceipt(receipt, { plan: activatePlan }), { ok: true, errors: [] }); assert.equal(validateEnginePrivateExtensionApplyReceipt({ ...receipt, state: "active" }) .errors.includes("apply_receipt_state_must_be_queued"), true); const activeOperation = { schemaVersion: ENGINE_PRIVATE_EXTENSION_OPERATION_SCHEMA_VERSION, operationId: receipt.operationId, planId: activatePlan.planId, planHash: activatePlan.planHash, action: "activate", state: "active", outcome: "committed", phase: "complete", expectedCurrentGeneration: 0, nextGeneration: 1, targetState: release, recoveryState: inactive, effectiveState: release, runtime: runtime(1, 2, 2), acceptance: acceptanceReport(release, "accepted"), updatedAt: "2026-07-15T18:00:32.000Z", }; assert.deepEqual(validateEnginePrivateExtensionOperation(activeOperation), { ok: true, errors: [] }); const unexpectedSchema = structuredClone(activeOperation); unexpectedSchema.acceptance.nodeTypes.observed.push("n8n-nodes-ndc.unreviewedNode"); assert.equal(validateEnginePrivateExtensionOperation(unexpectedSchema).errors .includes("acceptance.nodeTypes.observed_exact_set_required"), true); const automaticRollback = { ...activeOperation, state: "rolled-back", outcome: "automatically-rolled-back", phase: "complete", effectiveState: inactive, acceptance: acceptanceReport(inactive, "accepted"), errorCode: "runtime_acceptance_failed", }; assert.deepEqual(validateEnginePrivateExtensionOperation(automaticRollback), { ok: true, errors: [] }); assert.equal( validateEnginePrivateExtensionOperation({ ...automaticRollback, errorCode: undefined }) .errors.includes("errorCode_invalid"), true, ); const activeStatus = { schemaVersion: ENGINE_PRIVATE_EXTENSION_STATUS_SCHEMA_VERSION, packageName: ENGINE_PRIVATE_EXTENSION_PACKAGE_NAME, generation: 1, health: "ready", currentState: release, previousState: inactive, runtime: runtime(1, 2, 2), acceptance: acceptanceReport(release, "accepted"), updatedAt: "2026-07-15T18:00:33.000Z", }; assert.deepEqual(validateEnginePrivateExtensionStatus(activeStatus), { ok: true, errors: [] }); const rollbackRequest = { schemaVersion: ENGINE_PRIVATE_EXTENSION_PLAN_REQUEST_SCHEMA_VERSION, requestId: "extension-rollback-request-20260715-001", idempotencyKey: "extension-rollback-request-20260715-001", action: "rollback", requestedAt: "2026-07-15T18:05:00.000Z", requestExpiresAt: "2026-07-15T18:15:00.000Z", expectedCurrentGeneration: 1, target: { kind: "previous-state", packageName: ENGINE_PRIVATE_EXTENSION_PACKAGE_NAME }, }; assert.deepEqual(validateEnginePrivateExtensionPlanRequest(rollbackRequest, { now: "2026-07-15T18:05:01.000Z", grantedCapabilities: manage, }), { ok: true, errors: [] }); const rollbackPlan = withPlanHash({ schemaVersion: ENGINE_PRIVATE_EXTENSION_PLAN_SCHEMA_VERSION, planId: "extension-rollback-plan-20260715-001", planHash: hash("0"), requestId: rollbackRequest.requestId, idempotencyKey: rollbackRequest.idempotencyKey, action: "rollback", createdAt: "2026-07-15T18:05:01.000Z", expiresAt: "2026-07-15T18:14:00.000Z", singleUse: true, requiredCapability: ENGINE_PRIVATE_EXTENSION_MANAGE_CAPABILITY, expectedCurrentGeneration: 1, nextGeneration: 2, currentState: release, targetState: inactive, recoveryState: release, actions: [ "verify_previous_activation_state", "verify_community_package_loader_policy", "quiesce_deploy_run_and_drain_queue", "record_recovery_state", "atomic_switch_current_to_previous", "force_recreate_main_workers_webhooks_as_version_barrier", "verify_exact_runtime_acceptance", "commit_rolled_back_state", "resume_deploy_run", ], transition: transition(), acceptance: acceptanceSpec(inactive), failurePolicy: failurePolicy(), }); assert.deepEqual(validateEnginePrivateExtensionPlan(rollbackPlan, { request: rollbackRequest }), { ok: true, errors: [] }); const explicitRollbackOperation = { ...activeOperation, operationId: "extension-operation-rollback-20260715-001", planId: rollbackPlan.planId, planHash: rollbackPlan.planHash, action: "rollback", state: "rolled-back", outcome: "explicitly-rolled-back", expectedCurrentGeneration: 1, nextGeneration: 2, targetState: inactive, recoveryState: release, effectiveState: inactive, runtime: runtime(2, 2, 2), acceptance: acceptanceReport(inactive, "accepted"), }; assert.deepEqual(validateEnginePrivateExtensionOperation(explicitRollbackOperation), { ok: true, errors: [] }); const quarantinedStatus = { ...activeStatus, health: "quarantined", activeOperationId: "extension-operation-failed-20260715-001", acceptance: acceptanceReport(release, "rejected"), errorCode: "automatic_rollback_failed", }; assert.deepEqual(validateEnginePrivateExtensionStatus(quarantinedStatus), { ok: true, errors: [] }); const pathInjection = structuredClone(activateRequest); pathInjection.target.releaseId = "../../runtime"; assert.equal(validateEnginePrivateExtensionPlanRequest(pathInjection, { now: "2026-07-15T18:00:01.000Z", grantedCapabilities: manage, }).errors.includes("target.releaseId_invalid"), true); const commandInjection = { ...activateRequest, command: "docker exec runtime npm install" }; assert.equal(validateEnginePrivateExtensionPlanRequest(commandInjection, { now: "2026-07-15T18:00:01.000Z", grantedCapabilities: manage, }).errors.includes("enginePrivateExtensionPlanRequest.command_not_allowed"), true); console.log("external-provider Engine private-extension contract: ok"); function transition() { return { mountMode: "read-only", loaderMode: "community-package", loaderPath: "/home/node/.n8n/nodes/node_modules/n8n-nodes-ndc", loaderEnvironment: { N8N_COMMUNITY_PACKAGES_ENABLED: "true", N8N_COMMUNITY_PACKAGES_PREVENT_LOADING: "false", N8N_REINSTALL_MISSING_PACKAGES: "false", }, quiesceMode: "block-deploy-run-and-drain-queue", stateSwitch: "atomic-current-previous", runtimeAction: "force-recreate", scope: "main-workers-webhooks", requireUniformGeneration: true, hotReload: false, preserveCredentials: true, }; } function failurePolicy() { return { mode: "automatic-rollback", rollbackFailureOutcome: "quarantined", preserveImmutableRelease: true, preserveCredentials: true, }; } function acceptanceSpec(state) { return { mode: "exact", nodeTypes: state.kind === "release" ? [...ENGINE_PRIVATE_EXTENSION_NODE_TYPES] : [], credentialSchemas: state.kind === "release" ? [...ENGINE_PRIVATE_EXTENSION_CREDENTIAL_TYPES] : [], requireUniformGeneration: true, }; } function acceptanceReport(state, status) { const nodes = state.kind === "release" ? [...ENGINE_PRIVATE_EXTENSION_NODE_TYPES] : []; const credentials = state.kind === "release" ? [...ENGINE_PRIVATE_EXTENSION_CREDENTIAL_TYPES] : []; return { state: status, nodeTypes: { expected: nodes, observed: status === "pending" ? [] : nodes }, credentialSchemas: { expected: credentials, observed: status === "pending" ? [] : credentials }, uniformGeneration: status === "accepted", }; } function runtime(generation, expectedInstances, readyInstances) { return { mode: "force-recreate", generation, expectedInstances, readyInstances }; } function withPlanHash(plan) { plan.planHash = computeEnginePrivateExtensionPlanHash(plan); return plan; } function hash(character) { return "sha256:" + character.repeat(64); }