From 015443b7af2b55e3a1711672c3b699dd879ecaf4 Mon Sep 17 00:00:00 2001 From: Rhein1 / Agoragentic <140637602+rhein1@users.noreply.github.com> Date: Wed, 30 Sep 2026 09:39:42 -0400 Subject: [PATCH 01/15] fix(mcp): clear transitive dependency audit advisories --- mcp/package-lock.json | 12 ++++++------ mcp/package.json | 2 +- risk-fork-hosted-mcp/dist/runtime/index.mjs | 4 ++-- risk-fork-hosted-mcp/integrity-manifest.json | 8 ++++---- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/mcp/package-lock.json b/mcp/package-lock.json index 1cef2831..bb5eaaba 100644 --- a/mcp/package-lock.json +++ b/mcp/package-lock.json @@ -1041,9 +1041,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.7.tgz", - "integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", + "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", "dev": true, "funding": [ { @@ -1243,9 +1243,9 @@ "license": "ISC" }, "node_modules/ip-address": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.4.0.tgz", - "integrity": "sha512-oSK96Grm3aP6OrS263xVxbNDGVL7rzBtYdpGqlDG8iQdoenDoTs/nkki+DflYbAEE8Xl6o5YxhxlrKvI3nqKXQ==", + "version": "10.7.2", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.2.tgz", + "integrity": "sha512-7H/2gFSIitxc0hG3nOI1glS8QLo/EHBFFLk8vEUjXY/xu0AdL8jZ9U1IzO2PUm0d2D/ofQcAifb0g6OBkt8U7w==", "dev": true, "license": "MIT", "engines": { diff --git a/mcp/package.json b/mcp/package.json index c36ee9e5..6d6048af 100644 --- a/mcp/package.json +++ b/mcp/package.json @@ -64,7 +64,7 @@ }, "overrides": { "@hono/node-server": "2.0.11", - "fast-uri": "3.1.7", + "fast-uri": "3.1.8", "qs": "6.16.0" }, "engines": { diff --git a/risk-fork-hosted-mcp/dist/runtime/index.mjs b/risk-fork-hosted-mcp/dist/runtime/index.mjs index 04ae0296..b9528971 100644 --- a/risk-fork-hosted-mcp/dist/runtime/index.mjs +++ b/risk-fork-hosted-mcp/dist/runtime/index.mjs @@ -116,7 +116,7 @@ var require_package = __commonJS({ }, overrides: { "@hono/node-server": "2.0.11", - "fast-uri": "3.1.7", + "fast-uri": "3.1.8", qs: "6.16.0" }, engines: { @@ -74494,7 +74494,7 @@ function createE2BAuthorityFreeSourceVerifier(options = {}) { } // risk-fork-hosted-mcp/src/index.mjs -var REVIEWED_SOURCE_INTEGRITY = true ? "sha256:b376639a54275b44e3bb845c7d26aa63b7119f0ced68ebc6a7ca75e54f4a787f" : null; +var REVIEWED_SOURCE_INTEGRITY = true ? "sha256:7cf5b428998d43726f192359130d6c5d250507ab0cace2cc63fff273955b6739" : null; var HOSTED_MCP_BUNDLE_METADATA = Object.freeze({ package_name: "@agoragentic/risk-fork-hosted-mcp", package_version: "0.1.0-alpha.0", diff --git a/risk-fork-hosted-mcp/integrity-manifest.json b/risk-fork-hosted-mcp/integrity-manifest.json index ae74bf50..2c9f49cb 100644 --- a/risk-fork-hosted-mcp/integrity-manifest.json +++ b/risk-fork-hosted-mcp/integrity-manifest.json @@ -9,7 +9,7 @@ "schema": "agoragentic.risk-fork-hosted-mcp.reviewed-sources.v2", "normalization": "utf8_crlf_to_lf_lone_cr_preserved", "files": 66, - "sha256": "sha256:b376639a54275b44e3bb845c7d26aa63b7119f0ced68ebc6a7ca75e54f4a787f" + "sha256": "sha256:7cf5b428998d43726f192359130d6c5d250507ab0cace2cc63fff273955b6739" }, "reviewed_sources": [ { @@ -25,7 +25,7 @@ { "path": "mcp/package.json", "bytes": 3195, - "sha256": "sha256:bb551da95f41912a91b331e809f6195652b4d8bccd5881e94843d84b9f73c8d0" + "sha256": "sha256:f1810726d850cee5c84d2902e2ce108596e780d1cba573845f294d2cd59c85a1" }, { "path": "risk-fork/LICENSE", @@ -520,7 +520,7 @@ "path": "mcp/package.json", "source": "reviewed_source", "bytes": 3195, - "sha256": "sha256:bb551da95f41912a91b331e809f6195652b4d8bccd5881e94843d84b9f73c8d0" + "sha256": "sha256:f1810726d850cee5c84d2902e2ce108596e780d1cba573845f294d2cd59c85a1" }, { "path": "risk-fork-hosted-mcp/node_modules/@modelcontextprotocol/core/LICENSE", @@ -2629,7 +2629,7 @@ "artifact": { "path": "dist/runtime/index.mjs", "bytes": 3111081, - "sha256": "sha256:181a3ecf5788ee443595d4d7192c4c9bff50829e02ea6c52e9b842a2a74d6609" + "sha256": "sha256:c5e9814e13b84d5489527adeaac27e4d47363acec706cef3bcbe17f53e06dcc6" }, "packaged_assets": [ { From 59bc5d9692c7582df83a66f9b2103148610135ba Mon Sep 17 00:00:00 2001 From: rhein1 Date: Wed, 30 Sep 2026 10:07:23 -0400 Subject: [PATCH 02/15] fix(ci): refresh n8n and Claude SDK vulnerable transitive locks --- claude-agent-sdk/package-lock.json | 12 ++++++------ n8n/package-lock.json | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/claude-agent-sdk/package-lock.json b/claude-agent-sdk/package-lock.json index 7f11903f..8d7dd1e2 100644 --- a/claude-agent-sdk/package-lock.json +++ b/claude-agent-sdk/package-lock.json @@ -690,9 +690,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.7.tgz", - "integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", + "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", "dev": true, "funding": [ { @@ -893,9 +893,9 @@ "license": "ISC" }, "node_modules/ip-address": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.0.tgz", - "integrity": "sha512-BGFsyJd5mpXp3rK6jIdADLNgpJUK1jnjzvYF8lK+VyDab9JAmqN0YOKDdP17HlgKb2+ehPgDc8EtnRLbGCAMhA==", + "version": "10.7.2", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.2.tgz", + "integrity": "sha512-7H/2gFSIitxc0hG3nOI1glS8QLo/EHBFFLk8vEUjXY/xu0AdL8jZ9U1IzO2PUm0d2D/ofQcAifb0g6OBkt8U7w==", "dev": true, "license": "MIT", "engines": { diff --git a/n8n/package-lock.json b/n8n/package-lock.json index 28771282..c7c6fde4 100644 --- a/n8n/package-lock.json +++ b/n8n/package-lock.json @@ -227,9 +227,9 @@ "license": "MIT" }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", - "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", "dev": true, "license": "MIT", "dependencies": { @@ -305,9 +305,9 @@ "license": "MIT" }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", - "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", "dev": true, "license": "MIT", "dependencies": { @@ -1686,9 +1686,9 @@ } }, "node_modules/brace-expansion": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", - "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2352,9 +2352,9 @@ "license": "MIT" }, "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", - "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", "dev": true, "license": "MIT", "dependencies": { From fba3992f201cf4422956bd1e99b878142f71e392 Mon Sep 17 00:00:00 2001 From: Rhein1 / Agoragentic <140637602+rhein1@users.noreply.github.com> Date: Wed, 30 Sep 2026 09:39:42 -0400 Subject: [PATCH 03/15] fix(mcp): clear transitive dependency audit advisories --- mcp/package-lock.json | 12 ++++++------ mcp/package.json | 2 +- risk-fork-hosted-mcp/dist/runtime/index.mjs | 4 ++-- risk-fork-hosted-mcp/integrity-manifest.json | 8 ++++---- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/mcp/package-lock.json b/mcp/package-lock.json index 1cef2831..bb5eaaba 100644 --- a/mcp/package-lock.json +++ b/mcp/package-lock.json @@ -1041,9 +1041,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.7.tgz", - "integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", + "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", "dev": true, "funding": [ { @@ -1243,9 +1243,9 @@ "license": "ISC" }, "node_modules/ip-address": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.4.0.tgz", - "integrity": "sha512-oSK96Grm3aP6OrS263xVxbNDGVL7rzBtYdpGqlDG8iQdoenDoTs/nkki+DflYbAEE8Xl6o5YxhxlrKvI3nqKXQ==", + "version": "10.7.2", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.2.tgz", + "integrity": "sha512-7H/2gFSIitxc0hG3nOI1glS8QLo/EHBFFLk8vEUjXY/xu0AdL8jZ9U1IzO2PUm0d2D/ofQcAifb0g6OBkt8U7w==", "dev": true, "license": "MIT", "engines": { diff --git a/mcp/package.json b/mcp/package.json index c36ee9e5..6d6048af 100644 --- a/mcp/package.json +++ b/mcp/package.json @@ -64,7 +64,7 @@ }, "overrides": { "@hono/node-server": "2.0.11", - "fast-uri": "3.1.7", + "fast-uri": "3.1.8", "qs": "6.16.0" }, "engines": { diff --git a/risk-fork-hosted-mcp/dist/runtime/index.mjs b/risk-fork-hosted-mcp/dist/runtime/index.mjs index 04ae0296..b9528971 100644 --- a/risk-fork-hosted-mcp/dist/runtime/index.mjs +++ b/risk-fork-hosted-mcp/dist/runtime/index.mjs @@ -116,7 +116,7 @@ var require_package = __commonJS({ }, overrides: { "@hono/node-server": "2.0.11", - "fast-uri": "3.1.7", + "fast-uri": "3.1.8", qs: "6.16.0" }, engines: { @@ -74494,7 +74494,7 @@ function createE2BAuthorityFreeSourceVerifier(options = {}) { } // risk-fork-hosted-mcp/src/index.mjs -var REVIEWED_SOURCE_INTEGRITY = true ? "sha256:b376639a54275b44e3bb845c7d26aa63b7119f0ced68ebc6a7ca75e54f4a787f" : null; +var REVIEWED_SOURCE_INTEGRITY = true ? "sha256:7cf5b428998d43726f192359130d6c5d250507ab0cace2cc63fff273955b6739" : null; var HOSTED_MCP_BUNDLE_METADATA = Object.freeze({ package_name: "@agoragentic/risk-fork-hosted-mcp", package_version: "0.1.0-alpha.0", diff --git a/risk-fork-hosted-mcp/integrity-manifest.json b/risk-fork-hosted-mcp/integrity-manifest.json index ae74bf50..2c9f49cb 100644 --- a/risk-fork-hosted-mcp/integrity-manifest.json +++ b/risk-fork-hosted-mcp/integrity-manifest.json @@ -9,7 +9,7 @@ "schema": "agoragentic.risk-fork-hosted-mcp.reviewed-sources.v2", "normalization": "utf8_crlf_to_lf_lone_cr_preserved", "files": 66, - "sha256": "sha256:b376639a54275b44e3bb845c7d26aa63b7119f0ced68ebc6a7ca75e54f4a787f" + "sha256": "sha256:7cf5b428998d43726f192359130d6c5d250507ab0cace2cc63fff273955b6739" }, "reviewed_sources": [ { @@ -25,7 +25,7 @@ { "path": "mcp/package.json", "bytes": 3195, - "sha256": "sha256:bb551da95f41912a91b331e809f6195652b4d8bccd5881e94843d84b9f73c8d0" + "sha256": "sha256:f1810726d850cee5c84d2902e2ce108596e780d1cba573845f294d2cd59c85a1" }, { "path": "risk-fork/LICENSE", @@ -520,7 +520,7 @@ "path": "mcp/package.json", "source": "reviewed_source", "bytes": 3195, - "sha256": "sha256:bb551da95f41912a91b331e809f6195652b4d8bccd5881e94843d84b9f73c8d0" + "sha256": "sha256:f1810726d850cee5c84d2902e2ce108596e780d1cba573845f294d2cd59c85a1" }, { "path": "risk-fork-hosted-mcp/node_modules/@modelcontextprotocol/core/LICENSE", @@ -2629,7 +2629,7 @@ "artifact": { "path": "dist/runtime/index.mjs", "bytes": 3111081, - "sha256": "sha256:181a3ecf5788ee443595d4d7192c4c9bff50829e02ea6c52e9b842a2a74d6609" + "sha256": "sha256:c5e9814e13b84d5489527adeaac27e4d47363acec706cef3bcbe17f53e06dcc6" }, "packaged_assets": [ { From 164c2dae0a28c483e7f2169442f4c77eb042341b Mon Sep 17 00:00:00 2001 From: rhein1 Date: Wed, 30 Sep 2026 10:07:23 -0400 Subject: [PATCH 04/15] fix(ci): refresh n8n and Claude SDK vulnerable transitive locks --- claude-agent-sdk/package-lock.json | 12 ++++++------ n8n/package-lock.json | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/claude-agent-sdk/package-lock.json b/claude-agent-sdk/package-lock.json index 7f11903f..8d7dd1e2 100644 --- a/claude-agent-sdk/package-lock.json +++ b/claude-agent-sdk/package-lock.json @@ -690,9 +690,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.7.tgz", - "integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", + "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", "dev": true, "funding": [ { @@ -893,9 +893,9 @@ "license": "ISC" }, "node_modules/ip-address": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.0.tgz", - "integrity": "sha512-BGFsyJd5mpXp3rK6jIdADLNgpJUK1jnjzvYF8lK+VyDab9JAmqN0YOKDdP17HlgKb2+ehPgDc8EtnRLbGCAMhA==", + "version": "10.7.2", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.2.tgz", + "integrity": "sha512-7H/2gFSIitxc0hG3nOI1glS8QLo/EHBFFLk8vEUjXY/xu0AdL8jZ9U1IzO2PUm0d2D/ofQcAifb0g6OBkt8U7w==", "dev": true, "license": "MIT", "engines": { diff --git a/n8n/package-lock.json b/n8n/package-lock.json index 28771282..c7c6fde4 100644 --- a/n8n/package-lock.json +++ b/n8n/package-lock.json @@ -227,9 +227,9 @@ "license": "MIT" }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", - "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", "dev": true, "license": "MIT", "dependencies": { @@ -305,9 +305,9 @@ "license": "MIT" }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", - "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", "dev": true, "license": "MIT", "dependencies": { @@ -1686,9 +1686,9 @@ } }, "node_modules/brace-expansion": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", - "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2352,9 +2352,9 @@ "license": "MIT" }, "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", - "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", "dev": true, "license": "MIT", "dependencies": { From 1506500c6a2a6b481d31e8a16769febbbc50231b Mon Sep 17 00:00:00 2001 From: Rhein1 / Agoragentic <140637602+rhein1@users.noreply.github.com> Date: Wed, 30 Sep 2026 14:01:33 -0400 Subject: [PATCH 05/15] fix(governance): preserve action receipts across lifecycle failures --- .github/workflows/validate.yml | 1 + sdk/node/README.md | 10 ++ sdk/node/local-governance.js | 71 ++++---- sdk/python/README.md | 10 ++ sdk/python/src/agoragentic/governance.py | 21 ++- sdk/python/tests/test_governance_lifecycle.py | 158 ++++++++++++++++++ test/governance-lifecycle.test.mjs | 99 +++++++++++ 7 files changed, 339 insertions(+), 31 deletions(-) create mode 100644 sdk/python/tests/test_governance_lifecycle.py create mode 100644 test/governance-lifecycle.test.mjs diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index a106bcac..6376f9e2 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -132,6 +132,7 @@ jobs: run: | node --test test/sdk-public-source.test.mjs node --test test/local-governance-cli.test.mjs + node --test test/governance-lifecycle.test.mjs node --check sdk/node/index.js node --check sdk/node/index.mjs node --check sdk/agent-os-cli/cli.js diff --git a/sdk/node/README.md b/sdk/node/README.md index c3fd51f3..cfa13e51 100644 --- a/sdk/node/README.md +++ b/sdk/node/README.md @@ -94,6 +94,16 @@ const safeTool = govern(sendEmail, { The approval callback receives only the normalized action and argument count. Result evidence is shape-only by default, and raw tool inputs or outputs are not persisted. +Callback failures are recorded by phase. Approval failure produces `approval_failed` +without dispatch; evidence failure after a successful tool produces +`completed_evidence_failed`. A failed `onReceipt` raises `receipt_callback_failed` +with the original receipt in both `error.response.receipt` and +`error.agoragenticReceipt`, without writing a second action receipt. Approval, tool, +and evidence exceptions retain their identity and use the `agoragenticReceipt` +access convention when the thrown value can accept properties. `receipts: false` +disables persistence and supplies `null` to receipt callbacks. +These wrappers do not retry, resume, roll back effects, or provide restart-safe execution. + ## Hosted Router Model `agoragentic` is a thin client to the Agoragentic-hosted Agent OS router. diff --git a/sdk/node/local-governance.js b/sdk/node/local-governance.js index b4c66e08..a5237ce8 100644 --- a/sdk/node/local-governance.js +++ b/sdk/node/local-governance.js @@ -229,11 +229,22 @@ function govern(tool, options = {}) { prepareReceiptDirectory(policy, cwd); let approved = options.approved === true; const initial = evaluatePolicy(policy, action, { approved }); + const startedAt = nowIso(options); + const record = (decision, outcome, evidence) => writeReceipt(policy, cwd, buildReceipt({ + options, action, classification: 'local_tool_evidence', decision, + startedAt, finishedAt: nowIso(options), outcome, + evidence: { argument_count: args.length, ...evidence }, + })); if (initial.decision === 'ask' && !approved && typeof options.approve === 'function') { - approved = await options.approve({ action, argument_count: args.length }) === true; + try { + approved = await options.approve({ action, argument_count: args.length }) === true; + } catch (err) { + const receipt = record(initial, 'approval_failed', { error_code: safeErrorCode(err) }); + attachReceipt(err, receipt); + throw err; + } } const decision = evaluatePolicy(policy, action, { approved }); - const startedAt = nowIso(options); if (!decision.execute) { const receipt = writeReceipt(policy, cwd, buildReceipt({ options, @@ -248,42 +259,44 @@ function govern(tool, options = {}) { throw governanceError(decision.reason, `Action ${action} was not executed: ${decision.reason}.`, 3, { receipt }); } + let result; + try { + result = await tool(...args); + } catch (err) { + const receipt = record(decision, 'failed', { error_code: safeErrorCode(err) }); + attachReceipt(err, receipt); + throw err; + } + let evidence; try { - const result = await tool(...args); - const finishedAt = nowIso(options); - const evidence = typeof options.evidence === 'function' + evidence = typeof options.evidence === 'function' ? summarizeEvidence(await options.evidence(result)) : summarizeEvidence(result); - const receipt = writeReceipt(policy, cwd, buildReceipt({ - options, - action, - classification: 'local_tool_evidence', - decision, - startedAt, - finishedAt, - outcome: 'completed', - evidence: { argument_count: args.length, result: evidence }, - })); - if (typeof options.onReceipt === 'function') await options.onReceipt(receipt); - return result; } catch (err) { - const finishedAt = nowIso(options); - const receipt = writeReceipt(policy, cwd, buildReceipt({ - options, - action, - classification: 'local_tool_evidence', - decision, - startedAt, - finishedAt, - outcome: 'failed', - evidence: { argument_count: args.length, error_code: safeErrorCode(err) }, - })); - err.agoragenticReceipt = receipt; + const receipt = record(decision, 'completed_evidence_failed', { error_code: safeErrorCode(err) }); + attachReceipt(err, receipt); throw err; } + const receipt = record(decision, 'completed', { result: evidence }); + if (typeof options.onReceipt === 'function') { + try { + await options.onReceipt(receipt); + } catch (err) { + const error = governanceError('receipt_callback_failed', 'Receipt callback failed after the tool completed.', 1, { receipt }); + error.agoragenticReceipt = receipt; + error.cause = err; + throw error; + } + } + return result; }; } +function attachReceipt(error, receipt) { + // JavaScript permits primitive and frozen throws; preserve the original failure. + try { error.agoragenticReceipt = receipt; } catch { /* receipt remains on disk */ } +} + async function runGovernedCommand(executable, args = [], options = {}) { if (!executable || typeof executable !== 'string') { throw governanceError('command_missing', 'A command is required after "agoragentic run --".', 2); diff --git a/sdk/python/README.md b/sdk/python/README.md index ed8b8786..7f728a77 100644 --- a/sdk/python/README.md +++ b/sdk/python/README.md @@ -44,6 +44,16 @@ result = safe_tool(recipient="owner@example.com", body="review requested") The approval callback receives only the normalized action, argument count, and keyword names. Local receipts persist result shape rather than raw inputs or outputs, keep spend and retry authority owner-only, and cannot escape the project through configured paths. A receipt proves only the wrapped local call. It is not host, provider, deployment, payment, settlement, or on-chain proof. +Async cancellation propagates `asyncio.CancelledError` with the phase receipt in +`error.agoragentic_receipt`. Cancellation during approval records `approval_failed` +without dispatch; during the tool it records `cancelled_effect_uncertain`, which +does not mean rollback or safe retry. After tool success, cancellation during +evidence capture records `completed_evidence_failed`. Cancellation during receipt +notification retains the original completed receipt and its ID. Ordinary callback +failures retain the existing `GovernanceError.receipt` convention. Disabling +receipts supplies `None` and performs no receipt writes. Neither wrapper retries, +resumes, rolls back effects, or provides restart-safe execution. + ## Hosted Router Model `agoragentic` is a thin client to the Agoragentic-hosted Agent OS router. diff --git a/sdk/python/src/agoragentic/governance.py b/sdk/python/src/agoragentic/governance.py index 0dfd755e..7890f95a 100644 --- a/sdk/python/src/agoragentic/governance.py +++ b/sdk/python/src/agoragentic/governance.py @@ -7,6 +7,7 @@ from __future__ import annotations +import asyncio import functools import inspect import json @@ -259,6 +260,9 @@ async def wrapped(*args: Any, **kwargs: Any) -> Any: if inspect.isawaitable(approval_result): approval_result = await approval_result resolved_approval = approval_result is True + except asyncio.CancelledError as exc: + exc.agoragentic_receipt = _write_pre_execution_failure(context, request, "CancelledError") + raise except Exception as exc: error = GovernanceError("approval_failed", "Approval callback failed.") receipt = _write_pre_execution_failure(context, request, error.code) @@ -269,6 +273,12 @@ async def wrapped(*args: Any, **kwargs: Any) -> Any: _raise_if_blocked(context, decision, request) try: result = await tool(*args, **kwargs) + except asyncio.CancelledError as exc: + exc.agoragentic_receipt = _write_receipt( + context, decision, outcome="cancelled_effect_uncertain", + evidence=dict(request, error_code="CancelledError"), + ) + raise except Exception as exc: receipt = _write_failed_receipt(context, decision, request, exc) try: @@ -280,6 +290,10 @@ async def wrapped(*args: Any, **kwargs: Any) -> Any: evidence_result = options["evidence"](result) if options["evidence"] else result if inspect.isawaitable(evidence_result): evidence_result = await evidence_result + summary = _summarize_evidence(evidence_result) + except asyncio.CancelledError as exc: + exc.agoragentic_receipt = _write_evidence_failure(context, decision, request, exc) + raise except Exception as exc: error = GovernanceError( "evidence_failed", @@ -291,13 +305,16 @@ async def wrapped(*args: Any, **kwargs: Any) -> Any: context, decision, outcome="completed", - evidence=dict(request, result=_summarize_evidence(evidence_result)), + evidence=dict(request, result=summary), ) if options["on_receipt"]: try: callback_result = options["on_receipt"](receipt) if inspect.isawaitable(callback_result): await callback_result + except asyncio.CancelledError as exc: + exc.agoragentic_receipt = receipt + raise except Exception as exc: raise GovernanceError( "receipt_callback_failed", @@ -364,7 +381,7 @@ def _write_evidence_failure( context: Dict[str, Any], decision: Dict[str, Any], request: Dict[str, Any], - error: Exception, + error: BaseException, ) -> Optional[Dict[str, Any]]: return _write_receipt( context, diff --git a/sdk/python/tests/test_governance_lifecycle.py b/sdk/python/tests/test_governance_lifecycle.py new file mode 100644 index 00000000..af237eb6 --- /dev/null +++ b/sdk/python/tests/test_governance_lifecycle.py @@ -0,0 +1,158 @@ +import asyncio +import json +import tempfile +import unittest +from pathlib import Path + +from agoragentic.governance import GovernanceError, create_default_policy, govern + + +class CancellationTests(unittest.IsolatedAsyncioTestCase): + async def test_async_callback_failures_and_disabled_receipts(self): + for enabled in (True, False): + for phase in ("approval", "evidence", "notification"): + with self.subTest(enabled=enabled, phase=phase), tempfile.TemporaryDirectory() as root: + policy = create_default_policy() + calls = [] + delivered = [] + + async def fail(at): + if phase == at: + raise RuntimeError("private-callback-error") + + async def approve(request): + await fail("approval") + return True + + async def tool(payload): + calls.append(True) + return payload + + async def evidence(result): + await fail("evidence") + return result + + async def notify(receipt): + delivered.append(receipt) + await fail("notification") + + wrapped = govern(tool, action="tool.run", policy=policy, cwd=root, + receipts=enabled, approve=approve, evidence=evidence, on_receipt=notify) + with self.assertRaises(GovernanceError) as raised: + await wrapped("private-payload") + self.assertEqual(len(calls), 0 if phase == "approval" else 1) + files = list(Path(root, ".agoragentic/receipts").glob("*.json")) + self.assertEqual(len(files), int(enabled)) + if enabled: + raw = files[0].read_text() + receipt = json.loads(raw) + self.assertEqual(receipt["outcome"], {"approval": "approval_failed", + "evidence": "completed_evidence_failed", "notification": "completed"}[phase]) + self.assertEqual(raised.exception.receipt["receipt_id"], receipt["receipt_id"]) + self.assertNotIn("private-", raw) + if phase == "notification": + self.assertEqual(delivered[0]["receipt_id"], receipt["receipt_id"]) + else: + self.assertIsNone(raised.exception.receipt) + self.assertFalse(Path(root, ".agoragentic").exists()) + + async def test_integrated_policy_flow(self): + with tempfile.TemporaryDirectory() as root: + policy = create_default_policy() + policy["actions"] = {"*": {"decision": "deny"}, "file.read": {"decision": "allow"}, + "file.write": {"decision": "ask"}} + effects = [] + + async def read(): + return "ready" + + async def write(): + effects.append(True) + Path(root, "bounded.txt").write_text("one") + return "private-result" + + self.assertEqual(await govern(read, action="file.read", policy=policy, cwd=root)(), "ready") + with self.assertRaises(GovernanceError): + await govern(write, action="file.write", policy=policy, cwd=root)() + self.assertEqual(effects, []) + entered = asyncio.Event() + approved = asyncio.Future() + + async def approve(request): + entered.set() + return await approved + + task = asyncio.create_task(govern(write, action="file.write", policy=policy, + cwd=root, approve=approve)()) + await asyncio.wait_for(entered.wait(), 2) + self.assertEqual(effects, []) + approved.set_result(True) + self.assertEqual(await task, "private-result") + policy["actions"]["file.write"] = {"decision": "deny"} + with self.assertRaises(GovernanceError): + await govern(write, action="file.write", policy=policy, cwd=root, approved=True, + approve=lambda _: self.fail("deny bypass"))() + self.assertEqual(effects, [True]) + receipts = [json.loads(p.read_text()) for p in Path(root, ".agoragentic/receipts").glob("*.json")] + self.assertEqual(len(receipts), 4) + self.assertNotIn("private-result", json.dumps(receipts)) + + async def test_phase_cancellation_persists_one_receipt_and_propagates(self): + phases = ("approval", "tool", "evidence", "notification") + for phase, enabled in ((phase, enabled) for phase in phases for enabled in (True, False)): + with self.subTest(phase=phase, enabled=enabled), tempfile.TemporaryDirectory() as root: + policy = create_default_policy() + policy["actions"]["file.write"] = {"decision": "ask"} + entered = asyncio.Event() + delivered = [] + + async def pause(at): + if at == phase: + entered.set() + await asyncio.Future() + + async def approve(request): + await pause("approval") + return True + + async def tool(payload): + Path(root, "effect.txt").write_text("one bounded write") + await pause("tool") + return payload + + async def evidence(result): + await pause("evidence") + return result + + async def notify(receipt): + delivered.append(receipt) + await pause("notification") + + wrapped = govern(tool, action="file.write", policy=policy, cwd=root, + receipts=enabled, approve=approve, evidence=evidence, on_receipt=notify) + task = asyncio.create_task(wrapped("private-payload-and-error")) + await asyncio.wait_for(entered.wait(), 2) + task.cancel("private-payload-and-error") + with self.assertRaises(asyncio.CancelledError) as raised: + await task + self.assertTrue(task.cancelled()) + files = list(Path(root, ".agoragentic/receipts").glob("*.json")) + if not enabled: + self.assertEqual(files, []) + self.assertIsNone(raised.exception.agoragentic_receipt) + self.assertFalse(Path(root, ".agoragentic").exists()) + continue + self.assertEqual(len(files), 1) + raw = files[0].read_text() + receipt = json.loads(raw) + self.assertEqual(receipt["outcome"], { + "approval": "approval_failed", "tool": "cancelled_effect_uncertain", + "evidence": "completed_evidence_failed", "notification": "completed", + }[phase]) + self.assertEqual(Path(root, "effect.txt").exists(), phase != "approval") + self.assertNotIn("private-payload-and-error", raw) + self.assertEqual(raised.exception.agoragentic_receipt["receipt_id"], receipt["receipt_id"]) + for flag in ("provider_execution", "payment", "settlement"): + self.assertFalse(receipt["proof_scope"][flag]) + if phase == "notification": + self.assertEqual(delivered[0]["receipt_id"], receipt["receipt_id"]) diff --git a/test/governance-lifecycle.test.mjs b/test/governance-lifecycle.test.mjs new file mode 100644 index 00000000..00445d80 --- /dev/null +++ b/test/governance-lifecycle.test.mjs @@ -0,0 +1,99 @@ +import assert from 'node:assert/strict'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; +import { govern, createDefaultPolicy } from '../sdk/node/local-governance.mjs'; + +const secret = 'private-payload-and-error'; +for (const phase of ['approval', 'tool', 'evidence', 'notification']) { + test(`persist one truthful receipt on ${phase} failure`, async (t) => { + const cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'govern-lifecycle-')); + t.after(() => fs.rmSync(cwd, { recursive: true, force: true })); + const policy = createDefaultPolicy(); + policy.actions['file.write'] = { decision: phase === 'approval' ? 'ask' : 'allow' }; + let delivered; + const failure = new Error(secret); + const fail = () => { throw failure; }; + const wrapped = govern(() => { + fs.writeFileSync(path.join(cwd, 'effect.txt'), 'one bounded write'); + if (phase === 'tool') fail(); + return secret; + }, { + cwd, policy, action: 'file.write', + approve: fail, + evidence: phase === 'evidence' ? fail : undefined, + onReceipt: (receipt) => { delivered = receipt; if (phase === 'notification') fail(); }, + }); + let error; + try { await wrapped(secret); } catch (caught) { error = caught; } + assert.ok(error); + const files = fs.readdirSync(path.join(cwd, '.agoragentic/receipts')); + assert.equal(files.length, 1); + const raw = fs.readFileSync(path.join(cwd, '.agoragentic/receipts', files[0]), 'utf8'); + const receipt = JSON.parse(raw); + assert.equal(receipt.outcome, { approval: 'approval_failed', tool: 'failed', evidence: 'completed_evidence_failed', notification: 'completed' }[phase]); + assert.equal(fs.existsSync(path.join(cwd, 'effect.txt')), phase !== 'approval'); + assert.equal(receipt.schema, 'agoragentic.local-action-receipt.v1'); + assert.equal(receipt.decision.authority.retry, 'owner_only'); + for (const flag of ['provider_execution', 'payment', 'settlement']) assert.equal(receipt.proof_scope[flag], false); + assert.ok(!raw.includes(secret)); + assert.equal(error.agoragenticReceipt.receipt_id, receipt.receipt_id); + if (phase === 'notification') { + assert.equal(error.code, 'receipt_callback_failed'); + assert.equal(error.cause, failure); + assert.equal(delivered.receipt_id, receipt.receipt_id); + } else assert.equal(error, failure); + }); +} + +test('allow, paused ask, explicit approval, and deny share one bounded local fixture', async (t) => { + const cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'govern-flow-')); + t.after(() => fs.rmSync(cwd, { recursive: true, force: true })); + const policy = createDefaultPolicy(); + policy.actions = { '*': { decision: 'deny' }, 'file.read': { decision: 'allow' }, 'file.write': { decision: 'ask' } }; + const effects = []; + const tool = () => { effects.push(1); fs.writeFileSync(path.join(cwd, 'bounded.txt'), 'one'); return secret; }; + assert.equal(await govern(() => 'ready', { cwd, policy, action: 'file.read' })(), 'ready'); + await assert.rejects(govern(tool, { cwd, policy, action: 'file.write' })(), { code: 'explicit_approval_required' }); + assert.equal(effects.length, 0); + let approve; + let entered; + const pending = new Promise(resolve => { entered = resolve; }); + const invocation = govern(tool, { cwd, policy, action: 'file.write', approve: () => { + entered(); return new Promise(resolve => { approve = resolve; }); + } })(); + await pending; + assert.equal(effects.length, 0); + approve(true); + assert.equal(await invocation, secret); + assert.equal(effects.length, 1); + policy.actions['file.write'] = { decision: 'deny' }; + await assert.rejects(govern(tool, { cwd, policy, action: 'file.write', approved: true, + approve: () => assert.fail('deny must not call approval'), + })(), { code: 'policy_denied' }); + assert.equal(effects.length, 1); + const receipts = fs.readdirSync(path.join(cwd, '.agoragentic/receipts')).map(name => + JSON.parse(fs.readFileSync(path.join(cwd, '.agoragentic/receipts', name)))); + assert.equal(receipts.length, 4); + assert.equal(receipts.filter(r => r.outcome === 'completed').length, 2); + assert.ok(!JSON.stringify(receipts).includes(secret)); +}); + +test('receipts:false retains returns and failure phases without persistence', async (t) => { + const cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'govern-disabled-')); + t.after(() => fs.rmSync(cwd, { recursive: true, force: true })); + const policy = createDefaultPolicy(); + policy.default_decision = 'allow'; + const options = { cwd, policy, action: 'tool.run', receipts: false }; + let notified = 'unset'; + assert.equal(await govern(() => secret, { ...options, onReceipt: r => { notified = r; } })(), secret); + assert.equal(notified, null); + for (const failure of ['primitive', Object.freeze(new Error(secret))]) { + try { await govern(() => { throw failure; }, options)(); assert.fail('must throw'); } + catch (error) { assert.equal(error, failure); } + } + await assert.rejects(govern(() => secret, { ...options, onReceipt: () => { throw new Error(secret); } })(), + error => error.code === 'receipt_callback_failed' && error.agoragenticReceipt === null); + assert.equal(fs.existsSync(path.join(cwd, '.agoragentic')), false); +}); From 5ff6db1aced11a0dbf920c121980135a3201a4ec Mon Sep 17 00:00:00 2001 From: Rhein1 / Agoragentic <140637602+rhein1@users.noreply.github.com> Date: Wed, 30 Sep 2026 14:11:17 -0400 Subject: [PATCH 06/15] fix(governance): preserve cancellation when receipt persistence fails --- sdk/python/README.md | 7 +++ sdk/python/src/agoragentic/governance.py | 35 +++++++++--- sdk/python/tests/test_governance_lifecycle.py | 53 +++++++++++++++++++ 3 files changed, 89 insertions(+), 6 deletions(-) diff --git a/sdk/python/README.md b/sdk/python/README.md index 7f728a77..d84ead67 100644 --- a/sdk/python/README.md +++ b/sdk/python/README.md @@ -54,6 +54,13 @@ failures retain the existing `GovernanceError.receipt` convention. Disabling receipts supplies `None` and performs no receipt writes. Neither wrapper retries, resumes, rolls back effects, or provides restart-safe execution. +If receipt persistence fails while handling cancellation, the original +`CancelledError` still propagates and the task remains cancelled. +`agoragentic_receipt` is `None`; `agoragentic_receipt_error` contains only +`code: "receipt_persistence_failed"`, the phase, and the attempted outcome. +That marker is not a durable receipt or proof that a partial file was removed; +it contains no filesystem path or persistence-exception message. + ## Hosted Router Model `agoragentic` is a thin client to the Agoragentic-hosted Agent OS router. diff --git a/sdk/python/src/agoragentic/governance.py b/sdk/python/src/agoragentic/governance.py index 7890f95a..bde072f1 100644 --- a/sdk/python/src/agoragentic/governance.py +++ b/sdk/python/src/agoragentic/governance.py @@ -261,7 +261,8 @@ async def wrapped(*args: Any, **kwargs: Any) -> Any: approval_result = await approval_result resolved_approval = approval_result is True except asyncio.CancelledError as exc: - exc.agoragentic_receipt = _write_pre_execution_failure(context, request, "CancelledError") + _record_cancellation(context, context["initial"], request, exc, + phase="approval", outcome="approval_failed") raise except Exception as exc: error = GovernanceError("approval_failed", "Approval callback failed.") @@ -274,10 +275,8 @@ async def wrapped(*args: Any, **kwargs: Any) -> Any: try: result = await tool(*args, **kwargs) except asyncio.CancelledError as exc: - exc.agoragentic_receipt = _write_receipt( - context, decision, outcome="cancelled_effect_uncertain", - evidence=dict(request, error_code="CancelledError"), - ) + _record_cancellation(context, decision, request, exc, + phase="tool", outcome="cancelled_effect_uncertain") raise except Exception as exc: receipt = _write_failed_receipt(context, decision, request, exc) @@ -292,7 +291,8 @@ async def wrapped(*args: Any, **kwargs: Any) -> Any: evidence_result = await evidence_result summary = _summarize_evidence(evidence_result) except asyncio.CancelledError as exc: - exc.agoragentic_receipt = _write_evidence_failure(context, decision, request, exc) + _record_cancellation(context, decision, request, exc, + phase="evidence", outcome="completed_evidence_failed") raise except Exception as exc: error = GovernanceError( @@ -326,6 +326,29 @@ async def wrapped(*args: Any, **kwargs: Any) -> Any: return wrapped +def _record_cancellation( + context: Dict[str, Any], + decision: Dict[str, Any], + request: Dict[str, Any], + cancellation: asyncio.CancelledError, + *, + phase: str, + outcome: str, +) -> None: + # Persistence must never replace cancellation or imply a durable receipt + # when the write fails (including a partially written file). + cancellation.agoragentic_receipt = None + try: + cancellation.agoragentic_receipt = _write_receipt( + context, decision, outcome=outcome, + evidence=dict(request, error_code="CancelledError"), + ) + except Exception: + cancellation.agoragentic_receipt_error = { + "code": "receipt_persistence_failed", "phase": phase, "outcome": outcome, + } + + def _prepare_invocation(options: Dict[str, Any]) -> Dict[str, Any]: root = _project_root(options["cwd"]) loaded = load_policy(options["policy_source"], cwd=root) diff --git a/sdk/python/tests/test_governance_lifecycle.py b/sdk/python/tests/test_governance_lifecycle.py index af237eb6..35bda55f 100644 --- a/sdk/python/tests/test_governance_lifecycle.py +++ b/sdk/python/tests/test_governance_lifecycle.py @@ -8,6 +8,59 @@ class CancellationTests(unittest.IsolatedAsyncioTestCase): + async def test_cancellation_survives_receipt_persistence_failure_in_each_phase(self): + for phase in ("approval", "tool", "evidence"): + with self.subTest(phase=phase), tempfile.TemporaryDirectory() as root: + policy = create_default_policy() + entered = asyncio.Event() + cancellations = [] + + async def pause(at): + if at == phase: + entered.set() + try: + await asyncio.Future() + except asyncio.CancelledError as exc: + cancellations.append(exc) + raise + + async def approve(request): + await pause("approval") + return True + + async def tool(): + Path(root, "effect.txt").write_text("one bounded write") + await pause("tool") + return "private-result" + + async def evidence(result): + await pause("evidence") + return result + + task = asyncio.create_task(govern(tool, action="file.write", policy=policy, + cwd=root, approve=approve, evidence=evidence)()) + await asyncio.wait_for(entered.wait(), 2) + directory = Path(root, ".agoragentic", "receipts") + directory.rmdir() # Verified empty fixture directory, inside TemporaryDirectory. + directory.write_text("private-obstruction") + task.cancel("private-cancellation") + with self.assertRaises(asyncio.CancelledError) as raised: + await task + self.assertTrue(task.cancelled()) + self.assertIs(raised.exception, cancellations[0]) + self.assertIsNone(raised.exception.agoragentic_receipt) + self.assertEqual(raised.exception.agoragentic_receipt_error, { + "code": "receipt_persistence_failed", "phase": phase, + "outcome": {"approval": "approval_failed", "tool": "cancelled_effect_uncertain", + "evidence": "completed_evidence_failed"}[phase], + }) + self.assertEqual(Path(root, "effect.txt").exists(), phase != "approval") + self.assertEqual(directory.read_text(), "private-obstruction") + self.assertEqual(list(Path(root).rglob("*.json")), []) + marker = json.dumps(raised.exception.agoragentic_receipt_error) + self.assertNotIn("private-", marker) + self.assertNotIn(root, marker) + async def test_async_callback_failures_and_disabled_receipts(self): for enabled in (True, False): for phase in ("approval", "evidence", "notification"): From e1145d80c604a63d201c8e6fac20654643d1329d Mon Sep 17 00:00:00 2001 From: Rhein1 / Agoragentic <140637602+rhein1@users.noreply.github.com> Date: Wed, 30 Sep 2026 14:14:06 -0400 Subject: [PATCH 07/15] fix(governance): avoid invoking error code accessors --- sdk/node/local-governance.js | 9 ++++++- test/governance-lifecycle.test.mjs | 41 ++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/sdk/node/local-governance.js b/sdk/node/local-governance.js index a5237ce8..0237f8ba 100644 --- a/sdk/node/local-governance.js +++ b/sdk/node/local-governance.js @@ -464,7 +464,14 @@ function nowIso(options) { } function safeErrorCode(err) { - return typeof err?.code === 'string' && /^[A-Za-z0-9_.-]{1,64}$/.test(err.code) ? err.code : 'error'; + try { + // Inspect only the own data property: error accessors are untrusted + // executable code, and even descriptor inspection can throw on a Proxy. + const descriptor = Object.getOwnPropertyDescriptor(err, 'code'); + const code = descriptor?.value; + if (typeof code === 'string' && /^[A-Za-z0-9_.-]{1,64}$/.test(code)) return code; + } catch { /* primitive/revoked/hostile values retain a generic bounded code */ } + return 'error'; } function governanceError(code, message, exitCode = 1, response) { diff --git a/test/governance-lifecycle.test.mjs b/test/governance-lifecycle.test.mjs index 00445d80..1eb5cc68 100644 --- a/test/governance-lifecycle.test.mjs +++ b/test/governance-lifecycle.test.mjs @@ -6,6 +6,47 @@ import test from 'node:test'; import { govern, createDefaultPolicy } from '../sdk/node/local-governance.mjs'; const secret = 'private-payload-and-error'; +for (const phase of ['approval', 'tool', 'evidence']) { + for (const hostile of ['accessor', 'proxy']) { + test(`${phase} failure safely records a ${hostile} error code`, async (t) => { + const cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'govern-error-code-')); + t.after(() => fs.rmSync(cwd, { recursive: true, force: true })); + const policy = createDefaultPolicy(); + policy.default_decision = phase === 'approval' ? 'ask' : 'allow'; + let accessorCalls = 0; + let effects = 0; + const failure = hostile === 'accessor' + ? Object.defineProperty(new Error(secret), 'code', { get() { + accessorCalls += 1; + throw new Error('private-getter-error'); + } }) + : new Proxy(new Error(secret), { getOwnPropertyDescriptor() { + throw new Error('private-descriptor-error'); + } }); + const fail = () => { throw failure; }; + const wrapped = govern(() => { + effects += 1; + if (phase === 'tool') fail(); + return secret; + }, { cwd, policy, action: 'tool.run', approve: fail, + evidence: phase === 'evidence' ? fail : undefined }); + let caught; + try { await wrapped(); } catch (error) { caught = error; } + assert.equal(caught, failure); + assert.equal(accessorCalls, 0); + assert.equal(effects, phase === 'approval' ? 0 : 1); + const directory = path.join(cwd, '.agoragentic/receipts'); + const files = fs.readdirSync(directory); + assert.equal(files.length, 1); + const raw = fs.readFileSync(path.join(directory, files[0]), 'utf8'); + const receipt = JSON.parse(raw); + assert.equal(receipt.outcome, { approval: 'approval_failed', tool: 'failed', evidence: 'completed_evidence_failed' }[phase]); + assert.equal(receipt.evidence.error_code, 'error'); + assert.ok(!raw.includes('private-')); + }); + } +} + for (const phase of ['approval', 'tool', 'evidence', 'notification']) { test(`persist one truthful receipt on ${phase} failure`, async (t) => { const cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'govern-lifecycle-')); From 1cb4fb4cb473d23bd174d3ea3da779cbe835d30f Mon Sep 17 00:00:00 2001 From: Rhein1 / Agoragentic <140637602+rhein1@users.noreply.github.com> Date: Wed, 30 Sep 2026 14:22:40 -0400 Subject: [PATCH 08/15] fix(governance): retain nested receipts on cancellation write failure --- sdk/python/README.md | 7 ++- sdk/python/src/agoragentic/governance.py | 8 ++- sdk/python/tests/test_governance_lifecycle.py | 54 ++++++++++++++++++- 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/sdk/python/README.md b/sdk/python/README.md index d84ead67..0b43c0fc 100644 --- a/sdk/python/README.md +++ b/sdk/python/README.md @@ -56,8 +56,11 @@ resumes, rolls back effects, or provides restart-safe execution. If receipt persistence fails while handling cancellation, the original `CancelledError` still propagates and the task remains cancelled. -`agoragentic_receipt` is `None`; `agoragentic_receipt_error` contains only -`code: "receipt_persistence_failed"`, the phase, and the attempted outcome. +`agoragentic_receipt` is `None` unless a nested governed call already attached +its own durable receipt, which is retained on outer persistence failure. +`agoragentic_receipt_error` contains only `code: "receipt_persistence_failed"`, +the failed action identity, the phase, and the attempted outcome. An inner +action's retained receipt does not prove persistence for the failed outer action. That marker is not a durable receipt or proof that a partial file was removed; it contains no filesystem path or persistence-exception message. diff --git a/sdk/python/src/agoragentic/governance.py b/sdk/python/src/agoragentic/governance.py index bde072f1..42e4de46 100644 --- a/sdk/python/src/agoragentic/governance.py +++ b/sdk/python/src/agoragentic/governance.py @@ -337,7 +337,10 @@ def _record_cancellation( ) -> None: # Persistence must never replace cancellation or imply a durable receipt # when the write fails (including a partially written file). - cancellation.agoragentic_receipt = None + # A nested governed call may already have attached a durable receipt for + # its own action. Keep that receipt if this outer persistence attempt fails. + if not hasattr(cancellation, "agoragentic_receipt"): + cancellation.agoragentic_receipt = None try: cancellation.agoragentic_receipt = _write_receipt( context, decision, outcome=outcome, @@ -345,7 +348,8 @@ def _record_cancellation( ) except Exception: cancellation.agoragentic_receipt_error = { - "code": "receipt_persistence_failed", "phase": phase, "outcome": outcome, + "code": "receipt_persistence_failed", "phase": phase, + "action": context["action"], "outcome": outcome, } diff --git a/sdk/python/tests/test_governance_lifecycle.py b/sdk/python/tests/test_governance_lifecycle.py index 35bda55f..c83d1cb6 100644 --- a/sdk/python/tests/test_governance_lifecycle.py +++ b/sdk/python/tests/test_governance_lifecycle.py @@ -8,6 +8,58 @@ class CancellationTests(unittest.IsolatedAsyncioTestCase): + async def test_outer_persistence_failure_retains_inner_notification_receipt(self): + with tempfile.TemporaryDirectory() as root: + policy = create_default_policy() + policy["default_decision"] = "allow" + inner_root = Path(root, "inner") + inner_root.mkdir() + outer_root = Path(root, "outer") + outer_root.mkdir() + entered = asyncio.Event() + delivered = [] + cancellations = [] + + async def inner_tool(): + Path(inner_root, "effect.txt").write_text("one bounded write") + + async def notify(receipt): + delivered.append(receipt) + entered.set() + try: + await asyncio.Future() + except asyncio.CancelledError as exc: + cancellations.append(exc) + raise + + inner = govern(inner_tool, action="inner.write", policy=policy, + cwd=inner_root, on_receipt=notify) + + async def outer_tool(): + await inner() + + task = asyncio.create_task(govern(outer_tool, action="outer.run", policy=policy, + cwd=outer_root)()) + await asyncio.wait_for(entered.wait(), 2) + directory = outer_root / ".agoragentic" / "receipts" + directory.rmdir() + directory.write_text("obstruction") + task.cancel() + with self.assertRaises(asyncio.CancelledError) as raised: + await task + self.assertTrue(task.cancelled()) + self.assertIs(raised.exception, cancellations[0]) + self.assertIs(raised.exception.agoragentic_receipt, delivered[0]) + self.assertEqual(delivered[0]["action"], "inner.write") + persisted = json.loads((inner_root / delivered[0]["path"]).read_text()) + self.assertEqual(persisted["receipt_id"], delivered[0]["receipt_id"]) + self.assertEqual(persisted["outcome"], "completed") + self.assertEqual(raised.exception.agoragentic_receipt_error, { + "code": "receipt_persistence_failed", "phase": "tool", + "action": "outer.run", "outcome": "cancelled_effect_uncertain", + }) + self.assertEqual(len(list(Path(root).rglob("*.json"))), 1) + async def test_cancellation_survives_receipt_persistence_failure_in_each_phase(self): for phase in ("approval", "tool", "evidence"): with self.subTest(phase=phase), tempfile.TemporaryDirectory() as root: @@ -50,7 +102,7 @@ async def evidence(result): self.assertIs(raised.exception, cancellations[0]) self.assertIsNone(raised.exception.agoragentic_receipt) self.assertEqual(raised.exception.agoragentic_receipt_error, { - "code": "receipt_persistence_failed", "phase": phase, + "code": "receipt_persistence_failed", "phase": phase, "action": "file.write", "outcome": {"approval": "approval_failed", "tool": "cancelled_effect_uncertain", "evidence": "completed_evidence_failed"}[phase], }) From 1d95644033348fa34b89758900a4b6cc038422e6 Mon Sep 17 00:00:00 2001 From: Rhein1 / Agoragentic <140637602+rhein1@users.noreply.github.com> Date: Wed, 30 Sep 2026 14:28:43 -0400 Subject: [PATCH 09/15] fix(n8n): qualify audit-clean development workflow fixture --- n8n/TOOLCHAIN_AUDIT.md | 35 +- n8n/package-lock.json | 832 ++------------------------------------ n8n/package.json | 4 +- n8n/test/release.test.cjs | 4 +- 4 files changed, 59 insertions(+), 816 deletions(-) diff --git a/n8n/TOOLCHAIN_AUDIT.md b/n8n/TOOLCHAIN_AUDIT.md index 7c57b54d..6bb90c36 100644 --- a/n8n/TOOLCHAIN_AUDIT.md +++ b/n8n/TOOLCHAIN_AUDIT.md @@ -2,7 +2,7 @@ Original toolchain audit: 2026-09-13 (supersedes 2026-09-01) -Dependency-fixture refresh: 2026-09-25. Rechecked the manifest and lockfile, +Dependency-fixture refresh: 2026-09-30. Rechecked the manifest and lockfile, peer ranges, clean install, tests, lint, build, dependency audits, and package contents. Historical CLI compatibility and Creator Portal acceptance were not revalidated. @@ -17,8 +17,8 @@ revalidated. - Linter: `eslint@9.29.0` - Formatter: `prettier@3.9.6` - Compiler: `typescript@5.9.2` -- Development host fixture: `n8n-workflow@2.39.1` -- Exact workflow peer fixture: `zod@3.25.76` +- Development host fixture: `n8n-workflow@2.28.4` +- Exact workflow peer fixture: `zod@3.25.67` - Minimum consumer Node.js: 20.19 - Locked development and publishing Node.js: 24 - Install mode: committed lockfile plus `npm ci` @@ -30,6 +30,17 @@ publishing workflow. ## Coordinated compatibility decision +The 2.39.1 fixture and available 2.41.1 stable / 2.42.1 beta releases pin +`axios@1.18.0` exactly. Seven newly reported Axios advisories require 1.20.0; +substituting a lock entry cannot satisfy that pin, and overrides remain prohibited. +Use the latest pre-Axios 2.28 patch fixture, 2.28.4, with its exact Zod peer +3.25.67. Its complete development graph audits clean. Clean installation, tests, +lint, build, runtime imports and the offline error boundary pass. All eleven +generated code, declaration and static-asset files are byte-identical to the +2.39.1 build. This changes the development fixture only: package version, +runtime peer, Node consumer floor, node source and audit policy are unchanged. +Requalify a newer fixture once its published dependency graph is patched. + Every available `@n8n/node-cli` line checked from 0.40.0 through the current stable and beta releases pulls an AI/template-only dependency branch through `@n8n/ai-node-sdk`. That branch pins `@langchain/classic@1.0.27` and @@ -84,17 +95,16 @@ The rejected dependency majors remain incoherent with this source candidate: The release-contract test pins the complete supported set so a future isolated major bump cannot look valid after changing only one manifest line. -`n8n-workflow@2.39.1` is the pinned development fixture, not a runtime -constraint. Its exact peer is satisfied by `zod@3.25.76`. The published peer +`n8n-workflow@2.28.4` is the pinned development fixture, not a runtime +constraint. Its exact peer is satisfied by `zod@3.25.67`. The published peer remains `n8n-workflow: "*"`, so host n8n versions are not narrowed. These fixtures keep clean-install build tests deterministic and are not shipped in the package tarball. -The pinned workflow fixture's development graph includes `isolated-vm@7`, -whose declared engine is Node.js 24 or newer. The published community node does -not ship that fixture, so the consumer floor remains Node.js 20.19; repository -validation and trusted publishing use Node.js 24 to satisfy the complete locked -development graph without ignoring engine metadata. +The pinned workflow fixture's development graph includes `isolated-vm@6.2.0`. +The published community node does not ship that fixture, so the consumer floor +remains Node.js 20.19; repository validation and trusted publishing continue to +use Node.js 24 without ignoring engine metadata. ## Security boundary @@ -110,9 +120,8 @@ found 0 vulnerabilities The CLI/AI/LangChain branch and `uuid@10.0.0` are absent from the lockfile. The only resolved `uuid` is patched `uuid@11.1.1` beneath the pinned workflow -fixture. The 2.39.1 development graph resolves `@n8n/utils@1.47.0` and patched -`nanoid@3.3.18`, and adds `quickjs-emscripten@0.32.0` with its `@jitl` QuickJS -WASM packages. These lock entries are development-only. `npm run audit:dev` +fixture. The vulnerable Axios dependency branch is absent from this fixture. +These lock entries are development-only. `npm run audit:dev` rejects any advisory at any severity; there is no development allowlist. The prior `brace-expansion`, `ip-address`, and `undici` findings remain resolved diff --git a/n8n/package-lock.json b/n8n/package-lock.json index c7c6fde4..14af7cb9 100644 --- a/n8n/package-lock.json +++ b/n8n/package-lock.json @@ -15,11 +15,11 @@ "eslint-import-resolver-typescript": "4.4.5", "eslint-plugin-import-x": "4.17.1", "eslint-plugin-n8n-nodes-base": "2.0.0", - "n8n-workflow": "2.39.1", + "n8n-workflow": "2.28.4", "prettier": "3.9.6", "typescript": "5.9.2", "typescript-eslint": "8.70.0", - "zod": "3.25.76" + "zod": "3.25.67" }, "engines": { "node": ">=20.19.0" @@ -28,103 +28,6 @@ "n8n-workflow": "*" } }, - "node_modules/@apm-js-collab/code-transformer": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/@apm-js-collab/code-transformer/-/code-transformer-0.18.1.tgz", - "integrity": "sha512-u1Hb6bHjWtkSpiprwVP6YaHC1DTN4RAU3zYkUDUe7WMnJwdyU1pwTL9dFKiSJB9IiLue/EQovmyx6xhU7FFtAQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/estree": "^1.0.8", - "astring": "^1.9.0", - "esquery": "^1.7.0", - "meriyah": "^6.1.4", - "semifies": "^1.0.0", - "source-map": "^0.6.0" - }, - "bin": { - "code-transformer": "cli.js" - } - }, - "node_modules/@apm-js-collab/code-transformer-bundler-plugins": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/@apm-js-collab/code-transformer-bundler-plugins/-/code-transformer-bundler-plugins-0.7.4.tgz", - "integrity": "sha512-nAfOeZPSUAQvJa1iFT/5oCrTm5YQhMMrfCNthNnaXHZiOQhu1KGuLoIx7HtbAi3wfwaBYLaICPIeenIaEwcXIg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@apm-js-collab/code-transformer": "^0.18.1", - "es-module-lexer": "^2.1.0", - "magic-string": "^0.30.21", - "module-details-from-path": "^1.0.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@apm-js-collab/tracing-hooks": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@apm-js-collab/tracing-hooks/-/tracing-hooks-0.13.0.tgz", - "integrity": "sha512-mTvWz9rnQwx1U3h0XPTHaX7bgfkpipLLTQyjlC2cdhQpQEuoLT0AGzoydeoq2NxfEVv6fWOOETcSbb2nptleyw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@apm-js-collab/code-transformer": "^0.18.0", - "debug": "^4.4.1", - "module-details-from-path": "^1.0.4" - } - }, - "node_modules/@codemirror/autocomplete": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.0.tgz", - "integrity": "sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.17.0", - "@lezer/common": "^1.0.0" - } - }, - "node_modules/@codemirror/language": { - "version": "6.12.4", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.4.tgz", - "integrity": "sha512-1q4PaT+o6PbgpkJt4Q8Fv5XJxTy4FUZ4MWETtyiDw3J0Pyr9E2vqcKL+k9wcvjNTIsauxvE7OfmWj3FRPHQ76A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.23.0", - "@lezer/common": "^1.5.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0", - "style-mod": "^4.0.0" - } - }, - "node_modules/@codemirror/state": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.7.1.tgz", - "integrity": "sha512-9QzNDgE4EYDnAHfrTlR2lwiPciiOymLtwKK+8yHQzCc7GXhAP9xdEbEJFy2IWB1j9UGUl9BsgMmTo/ImA02T7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@marijn/find-cluster-break": "^1.0.0" - } - }, - "node_modules/@codemirror/view": { - "version": "6.43.9", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.43.9.tgz", - "integrity": "sha512-sTuUzTpPMFebRhg6dawChoKKgndIwfjmJgKVxBefPElcU2NwQ6AFroupk0SFqEerQyZOGRfDNnSN8Dw/lMAsXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@codemirror/state": "^6.7.0", - "crelt": "^1.0.6", - "style-mod": "^4.1.0", - "w3c-keyname": "^2.2.4" - } - }, "node_modules/@emnapi/core": { "version": "1.11.3", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.3.tgz", @@ -441,105 +344,10 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@jitl/quickjs-ffi-types": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@jitl/quickjs-ffi-types/-/quickjs-ffi-types-0.32.0.tgz", - "integrity": "sha512-v9T+GQpmk43VDJ7d72sf0Nexhk+ArvtUihW27dy7lqAl0zBObFKtSBBIm5RBjwIhE8VwsPPm9PNuvPvNqLWUEg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jitl/quickjs-wasmfile-debug-asyncify": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@jitl/quickjs-wasmfile-debug-asyncify/-/quickjs-wasmfile-debug-asyncify-0.32.0.tgz", - "integrity": "sha512-EX8zbXwGqCgAE764M+qvkHtyXDi/FUoMBea0JnES7vCM3P7a2+EOZOjGv85wtZ2sJhI1oJ+nekmqpOODFDY+hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jitl/quickjs-ffi-types": "0.32.0" - } - }, - "node_modules/@jitl/quickjs-wasmfile-debug-sync": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@jitl/quickjs-wasmfile-debug-sync/-/quickjs-wasmfile-debug-sync-0.32.0.tgz", - "integrity": "sha512-LeYWrPGC1uNCTBWvibo3ZLJj0CSVNYUXvJpXMCmuQ5Sap2cCACc3uvGvYV4homHHBAzfw5akoTqMMS4YFRtw+Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jitl/quickjs-ffi-types": "0.32.0" - } - }, - "node_modules/@jitl/quickjs-wasmfile-release-asyncify": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@jitl/quickjs-wasmfile-release-asyncify/-/quickjs-wasmfile-release-asyncify-0.32.0.tgz", - "integrity": "sha512-3oSwPfja12ICz4aIblB58cuY8JlEq5Txt8Cut4VLo+LH47QN+mzCnSgnbB03hWzg1LBcc+VyyI9UOag7a1NF+Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jitl/quickjs-ffi-types": "0.32.0" - } - }, - "node_modules/@jitl/quickjs-wasmfile-release-sync": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@jitl/quickjs-wasmfile-release-sync/-/quickjs-wasmfile-release-sync-0.32.0.tgz", - "integrity": "sha512-BKNDI/TPBfGlLNGYpLrhcDGXmIk4xHm4MRAisOBnOzpXVn9HZWsfmMAc9WMBrAHjvvds6HOikKeaOBKdPdpVrg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jitl/quickjs-ffi-types": "0.32.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@lezer/common": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.2.tgz", - "integrity": "sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@lezer/highlight": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz", - "integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@lezer/common": "^1.3.0" - } - }, - "node_modules/@lezer/lr": { - "version": "1.4.10", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.10.tgz", - "integrity": "sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@lezer/common": "^1.0.0" - } - }, - "node_modules/@marijn/find-cluster-break": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.3.tgz", - "integrity": "sha512-FY+MKLBoTsLNJF/eLWaOsXGdz6uh3Iu1axjPf6TUq92IYumcTcXWHoS747JARLkcdlJ/Waiaxc5wQfFO8jC6NA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@n8n/constants": { - "version": "0.38.0", - "resolved": "https://registry.npmjs.org/@n8n/constants/-/constants-0.38.0.tgz", - "integrity": "sha512-xcAHwgKl17ZQS1RFAwjit95dr/AL53WlLqmAcUIFi+A9cTr494aD00RBO/egACTycOY1ZWTst2D1B7jlHpESkg==", - "dev": true, - "license": "SEE LICENSE IN LICENSE.md" - }, "node_modules/@n8n/errors": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@n8n/errors/-/errors-0.13.0.tgz", - "integrity": "sha512-hUZ+ePKp2BzJL40OK1+wTVefJkKLy+mjiBT6KsejkXi1HboYoqHruFqeQZivm5PHhX3CZsHa9ZJy2LGHZrpKCQ==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@n8n/errors/-/errors-0.10.0.tgz", + "integrity": "sha512-Qle4gCsx7qtDRMdie3YkjuXPuo369PP32cR9Svb+INwcjLMxNzmnbJ66jFnOmLn0ntwBccUw1IecJ6axwyTgBQ==", "dev": true, "license": "SEE LICENSE IN LICENSE.md", "dependencies": { @@ -563,48 +371,40 @@ } }, "node_modules/@n8n/expression-runtime": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/@n8n/expression-runtime/-/expression-runtime-0.30.0.tgz", - "integrity": "sha512-mC8yM8+eh0uuN7ZVwvERf/CVUN9hOiaAKG+QtKzfXrFaYSt5AwNXktTsmAdWsLEfH1HjBBXaMc3eMF4IaifPoA==", + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@n8n/expression-runtime/-/expression-runtime-0.19.1.tgz", + "integrity": "sha512-tv86UUD+uBqORBOH70BQaRRXYfatPlygvhk80a4dO2SEubXzIFQxshMb1oA7loEj9ZMeYQesUotvgN57JbPQgA==", "dev": true, "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@n8n/errors": "0.13.0", - "@n8n/tournament": "1.11.0", - "isolated-vm": "^7.0.0", + "@n8n/errors": "0.10.0", + "@n8n/tournament": "1.4.0", + "isolated-vm": "^6.1.2", "jmespath": "0.16.0", "js-base64": "3.7.8", "jssha": "3.3.1", "lodash": "4.18.1", "luxon": "3.7.2", "md5": "2.3.0", - "quickjs-emscripten": "^0.32.0", "title-case": "3.0.3", "transliteration": "2.3.5", - "zod": "3.25.76" + "zod": "3.25.67" } }, "node_modules/@n8n/tournament": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@n8n/tournament/-/tournament-1.11.0.tgz", - "integrity": "sha512-cwu7t9UTTwAPDhGRjY03dRiWeR01wavkj2yWBEN/Rs0og17SvJqfgJ4z7Wgsiha8+iwg+mZ/l+Fv4uEhC5F3FQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@n8n/tournament/-/tournament-1.4.0.tgz", + "integrity": "sha512-llDdmIj3Kdfq2vX/NpLBOUU4kLjhITtIMeJmOSTApAOeAArj1D45ey4D7CFaYcYsPBw6DgF0vxifyskPDlgekw==", "dev": true, "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "ast-types": "^0.16.1", "esprima-next": "^5.8.4", "recast": "^0.22.0" - } - }, - "node_modules/@n8n/utils": { - "version": "1.47.0", - "resolved": "https://registry.npmjs.org/@n8n/utils/-/utils-1.47.0.tgz", - "integrity": "sha512-/wE1a/EEZWqFdJkeEqMp971hDvI2noDSVwQDm1AHFv5oW23h5kVTeG2SySVMWcGZYgnc5bl6Mvcrt35vaSFasg==", - "dev": true, - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@n8n/constants": "0.38.0", - "nanoid": "3.3.18" + }, + "engines": { + "node": ">=20.15", + "pnpm": ">=9.5" } }, "node_modules/@napi-rs/wasm-runtime": { @@ -626,247 +426,6 @@ "@emnapi/runtime": "^1.7.1" } }, - "node_modules/@opentelemetry/api": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", - "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/api-logs": { - "version": "0.220.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.220.0.tgz", - "integrity": "sha512-CmVa4ImJ+ynfrPMNaAXHET6Bhb44SwzmfyVJFq9ni2jgXJR/l7C6gfVFddNmHP+ZOkP9cf4f9DBe68qVLTHc9w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/core": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.10.0.tgz", - "integrity": "sha512-/wNZ8twnEQQA4HoHu22+vcsdru6pWPWxW+7w+FlxT6Id7PE/WIbZmVKkte+PF72e0F2dnImFeHD2syyE1Mw6MQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/instrumentation": { - "version": "0.220.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.220.0.tgz", - "integrity": "sha512-xQx3E2WxP1mDvKzxLxX+CTCtNLa560YJZ3087qYHerl2YmiKpv7AH+dAy7vmx+eVrZ5BwhfWUAVoKOoxCNHcpw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.220.0", - "import-in-the-middle": "^3.0.0", - "require-in-the-middle": "^8.0.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/resources": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.10.0.tgz", - "integrity": "sha512-q6MMm2zhggzsHVNbabYwut+a6nbuQQe3URUoxaojM/8K1IBfwwPzvxIjNi2/lI1TFe+fMHMW9MWhrtDLEXEnkA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.10.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-trace": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace/-/sdk-trace-2.10.0.tgz", - "integrity": "sha512-MfQGq3GRmTh5fM/y+OjaO0vj6+luCB1XO2gfXCalKCfgKw0eHL++sm75DNweC6ohlp+aFvACqeE0fYayqdRaoQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.10.0", - "@opentelemetry/resources": "2.10.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.10.0.tgz", - "integrity": "sha512-GuYQQT7QD2EeO8lcZLRQzcbOyhqAzL+6WWTKTU9mSUBYBazkEDl+VrQcXQhbB08OWM9anD1aHleVadzulpOaUQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.10.0", - "@opentelemetry/resources": "2.10.0", - "@opentelemetry/sdk-trace": "2.10.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.43.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.43.0.tgz", - "integrity": "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/@sentry/conventions": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@sentry/conventions/-/conventions-0.16.0.tgz", - "integrity": "sha512-fO9PLmHdVURcSPUpWCItWAtgKiMwGdJHbovoSEyLplX5sxs2ugvI4CBPTrkkgqhObnZOD0CnWBKDzSVQYBKEyQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - } - }, - "node_modules/@sentry/core": { - "version": "10.70.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.70.0.tgz", - "integrity": "sha512-ozhCTDqg89oB4XmWfAwuHshABpvT7AkRpaPnogopPfMAaI61G1t8EKCJ4W7aum8JSBonlfyjPCyW5oYZFm0KvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sentry/conventions": "^0.16.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@sentry/node": { - "version": "10.70.0", - "resolved": "https://registry.npmjs.org/@sentry/node/-/node-10.70.0.tgz", - "integrity": "sha512-SPOOVxmKTVIEtqvOKkQT163e/pOwucjS7OPsCHyRs8sFR4nfBNu0EThplyqnvqd5BWBMTPH6WTBQfo+QWHV+HA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@opentelemetry/api": "^1.9.1", - "@opentelemetry/instrumentation": "^0.220.0", - "@opentelemetry/sdk-trace-base": "^2.9.0", - "@sentry/conventions": "^0.16.0", - "@sentry/core": "10.70.0", - "@sentry/node-core": "10.70.0", - "@sentry/opentelemetry": "10.70.0", - "@sentry/server-utils": "10.70.0", - "import-in-the-middle": "^3.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@sentry/node-core": { - "version": "10.70.0", - "resolved": "https://registry.npmjs.org/@sentry/node-core/-/node-core-10.70.0.tgz", - "integrity": "sha512-oPOEVVNxv5WHtckx2i06Wi9FLWyvOg/1DUeX732jZ4iqT2nupINaMH4nF4f4kSvUThFnxkFSRQxwqOxgzMKhKA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sentry/conventions": "^0.16.0", - "@sentry/core": "10.70.0", - "@sentry/opentelemetry": "10.70.0", - "import-in-the-middle": "^3.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.9.0", - "@opentelemetry/core": "^1.30.1 || ^2.1.0", - "@opentelemetry/exporter-trace-otlp-http": ">=0.57.0 <1", - "@opentelemetry/instrumentation": ">=0.57.1 <1", - "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0" - }, - "peerDependenciesMeta": { - "@opentelemetry/api": { - "optional": true - }, - "@opentelemetry/core": { - "optional": true - }, - "@opentelemetry/exporter-trace-otlp-http": { - "optional": true - }, - "@opentelemetry/instrumentation": { - "optional": true - }, - "@opentelemetry/sdk-trace-base": { - "optional": true - } - } - }, - "node_modules/@sentry/opentelemetry": { - "version": "10.70.0", - "resolved": "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-10.70.0.tgz", - "integrity": "sha512-UNV/2tqypcUK6FDzerAsFJn1Km/c4VZCYkUZDNbnV5S0cwAq2BYKMo4M5vovaLDBQlxA+Wk9ovbxi5wYjjl9fw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sentry/conventions": "^0.16.0", - "@sentry/core": "10.70.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.9.0", - "@opentelemetry/core": "^1.30.1 || ^2.1.0", - "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0" - } - }, - "node_modules/@sentry/server-utils": { - "version": "10.70.0", - "resolved": "https://registry.npmjs.org/@sentry/server-utils/-/server-utils-10.70.0.tgz", - "integrity": "sha512-rzegZjMFFgCp3o+N8+XU13rfSvz4B+f8rU0ijBGrQcHdMNyfsFDTu1UTm262JofmrV2u+s+D0u0vFTnqtOGkbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@apm-js-collab/code-transformer-bundler-plugins": "^0.7.3", - "@apm-js-collab/tracing-hooks": "^0.13.0", - "@sentry/conventions": "^0.16.0", - "@sentry/core": "10.70.0", - "meriyah": "^6.1.4" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/@tybys/wasm-util": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", @@ -1545,16 +1104,6 @@ "dev": true, "license": "Python-2.0" }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, "node_modules/assert": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", @@ -1582,16 +1131,6 @@ "node": ">=4" } }, - "node_modules/astring": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", - "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", - "dev": true, - "license": "MIT", - "bin": { - "astring": "bin/astring" - } - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -1615,56 +1154,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/axios": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.18.0.tgz", - "integrity": "sha512-E32NzpYKp++W7XRe52rHiXV2ehxmh3wbdgO7MHeFM+vqxLBYHzt0ElkiImtOBxtOmyp0yoC8C6uESVV84Y2/hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.16.0", - "form-data": "^4.0.5", - "https-proxy-agent": "^5.0.1", - "proxy-from-env": "^2.1.0" - } - }, - "node_modules/axios/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/axios/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/axios/node_modules/proxy-from-env": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", - "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, "node_modules/balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", @@ -1675,16 +1164,6 @@ "node": "18 || 20 || >=22" } }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, "node_modules/brace-expansion": { "version": "5.0.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", @@ -1698,16 +1177,6 @@ "node": "20 || >=22" } }, - "node_modules/buildcheck": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.7.tgz", - "integrity": "sha512-lHblz4ahamxpTmnsk+MNTRWsjYKv965MwOrSJyeD588rR3Jcu7swE+0wN5F+PbL5cjgu/9ObkhfzEPuofEMwLA==", - "dev": true, - "optional": true, - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/call-bind": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", @@ -1819,13 +1288,6 @@ "node": "*" } }, - "node_modules/cjs-module-lexer": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.1.tgz", - "integrity": "sha512-Ca8swihM+/4yKecYHY52kgJd300hi2lADU/a1RxNTRe+RJ9jvqQlESpbz9DnG9mowez8qwXHB8qYdIUw9e+F5Q==", - "dev": true, - "license": "MIT" - }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -1891,28 +1353,6 @@ "dev": true, "license": "MIT" }, - "node_modules/cpu-features": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.10.tgz", - "integrity": "sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "dependencies": { - "buildcheck": "~0.0.6", - "nan": "^2.19.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/crelt": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.7.tgz", - "integrity": "sha512-aK6BbWfhf4U/wCcLHKPJl/xa6VkVstRaPywWtMKGwuOLc/wZTyQYuoxgvZnNsBvv7Kg3YTBQYYBCggcviQczuA==", - "dev": true, - "license": "MIT" - }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -2051,13 +1491,6 @@ "node": ">= 0.4" } }, - "node_modules/es-module-lexer": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", - "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", - "dev": true, - "license": "MIT" - }, "node_modules/es-object-atoms": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", @@ -2559,27 +1992,6 @@ "dev": true, "license": "ISC" }, - "node_modules/follow-redirects": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", - "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, "node_modules/for-each": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", @@ -2826,21 +2238,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-in-the-middle": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-3.3.3.tgz", - "integrity": "sha512-AiohS3H80sXO6owEltjGX+glb7qXaDhBoJb9XcQVH4UI207xu/bDLUcadVKp7Qe576reg9yr/PXZjV5qx8gfbA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "cjs-module-lexer": "^2.2.0", - "es-module-lexer": "^2.2.0", - "module-details-from-path": "^1.0.4" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -3028,9 +2425,9 @@ "license": "ISC" }, "node_modules/isolated-vm": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/isolated-vm/-/isolated-vm-7.0.1.tgz", - "integrity": "sha512-nBCQ1hXEaYKYJ79wwfhaF44ITOJC30Hw0wPEsFeNsdD3hdeKK7FW1SGMQYBUA+qasvkqdOazI+iBuq0lcbN/aw==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/isolated-vm/-/isolated-vm-6.2.0.tgz", + "integrity": "sha512-UuSlxSHWt2QuJ5WvBhzlIJx2VVZN/a44SqBbEZFKNdvuSyhOvhmyDo8SQ+njVbhnh/njoL/aW0bUTiFYlpweGQ==", "dev": true, "hasInstallScript": true, "license": "ISC", @@ -3038,7 +2435,7 @@ "node-gyp-build": "^4.8.4" }, "engines": { - "node": ">=24.0.0" + "node": ">=22.0.0" } }, "node_modules/jmespath": { @@ -3088,13 +2485,6 @@ "dev": true, "license": "MIT" }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true, - "license": "(AFL-2.1 OR BSD-3-Clause)" - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -3203,16 +2593,6 @@ "node": ">=12" } }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -3235,16 +2615,6 @@ "is-buffer": "~1.1.6" } }, - "node_modules/meriyah": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/meriyah/-/meriyah-6.1.4.tgz", - "integrity": "sha512-Sz8FzjzI0kN13GK/6MVEsVzMZEPvOhnmmI1lU5+/1cGOiK3QUahntrNNtdVeihrO7t9JpoH75iMNXg6R6uWflQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -3284,13 +2654,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/module-details-from-path": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz", - "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==", - "dev": true, - "license": "MIT" - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -3299,42 +2662,34 @@ "license": "MIT" }, "node_modules/n8n-workflow": { - "version": "2.39.1", - "resolved": "https://registry.npmjs.org/n8n-workflow/-/n8n-workflow-2.39.1.tgz", - "integrity": "sha512-nN6Wctmwr8O/e1mxmjXA58PbAtbmHQf0tYFHExRW4ZvmgwpowJ/VZBxEaCia2HwtzippmdfCj8ckTQbQnibvRw==", + "version": "2.28.4", + "resolved": "https://registry.npmjs.org/n8n-workflow/-/n8n-workflow-2.28.4.tgz", + "integrity": "sha512-wNWCEvk5eBxnp5p2y/6FpMsA5t6XZVBm8HIV/u1XiUX/p91UtdBvQW0f8tTr4B79G1aeKl/l8cSroit/WFuK6A==", "dev": true, "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@codemirror/autocomplete": "6.20.0", - "@n8n/constants": "0.38.0", - "@n8n/errors": "0.13.0", - "@n8n/expression-runtime": "0.30.0", - "@n8n/tournament": "1.11.0", - "@n8n/utils": "1.47.0", - "@sentry/core": "10.70.0", - "@sentry/node": "10.70.0", + "@n8n/errors": "0.10.0", + "@n8n/expression-runtime": "0.19.1", + "@n8n/tournament": "1.4.0", "ast-types": "0.16.1", - "axios": "1.18.0", "callsites": "3.1.0", "esprima-next": "5.8.4", "form-data": "4.0.6", "jmespath": "0.16.0", "js-base64": "3.7.8", - "json-schema": "0.4.0", "jsonrepair": "3.13.2", "jssha": "3.3.1", "lodash": "4.18.1", "luxon": "3.7.2", "md5": "2.3.0", "recast": "0.22.0", - "ssh2": "1.15.0", "title-case": "3.0.3", "transliteration": "2.3.5", "uuid": "11.1.1", "xml2js": "0.6.2" }, "peerDependencies": { - "zod": "3.25.76" + "zod": "3.25.67" } }, "node_modules/n8n-workflow/node_modules/uuid": { @@ -3351,33 +2706,6 @@ "uuid": "dist/esm/bin/uuid" } }, - "node_modules/nan": { - "version": "2.28.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.28.0.tgz", - "integrity": "sha512-fTsDz99OTq2sVePhGdp4qQhggZFtKr64ZNVyVajRKtMOkJxYekplBh577PiJB12v/D3s2E5cGtOI45LWp6rnLQ==", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/nanoid": { - "version": "3.3.18", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", - "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/napi-postinstall": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", @@ -3622,33 +2950,6 @@ "node": ">=6" } }, - "node_modules/quickjs-emscripten": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/quickjs-emscripten/-/quickjs-emscripten-0.32.0.tgz", - "integrity": "sha512-So0Sqw869y/S2oE3Nuc0uT3Dhqgvsj8FSrwBdsuTosVsG8ME5/OcudU1GxsrIFdFABgy17GHnTVO9TYV/bLQcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jitl/quickjs-wasmfile-debug-asyncify": "0.32.0", - "@jitl/quickjs-wasmfile-debug-sync": "0.32.0", - "@jitl/quickjs-wasmfile-release-asyncify": "0.32.0", - "@jitl/quickjs-wasmfile-release-sync": "0.32.0", - "quickjs-emscripten-core": "0.32.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/quickjs-emscripten-core": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/quickjs-emscripten-core/-/quickjs-emscripten-core-0.32.0.tgz", - "integrity": "sha512-QFnPfjFey8EqknSrSxe1hZrf1/8z7/6s1QzGOmKo6++02r7QRRX7ZoyNaZh7JuVjWsVW87KnQrbZqnHkOAzUyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jitl/quickjs-ffi-types": "0.32.0" - } - }, "node_modules/recast": { "version": "0.22.0", "resolved": "https://registry.npmjs.org/recast/-/recast-0.22.0.tgz", @@ -3689,20 +2990,6 @@ "node": ">=0.10.0" } }, - "node_modules/require-in-the-middle": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-8.0.1.tgz", - "integrity": "sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.5", - "module-details-from-path": "^1.0.3" - }, - "engines": { - "node": ">=9.3.0 || >=8.10.0 <9.0.0" - } - }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -3741,13 +3028,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "license": "MIT" - }, "node_modules/sax": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz", @@ -3758,13 +3038,6 @@ "node": ">=11.0.0" } }, - "node_modules/semifies": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semifies/-/semifies-1.0.0.tgz", - "integrity": "sha512-xXR3KGeoxTNWPD4aBvL5NUpMTT7WMANr3EWnaS190QVkY52lqqcVRD7Q05UVbBhiWDGWMlJEUam9m7uFFGVScw==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/semver": { "version": "7.8.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", @@ -3841,24 +3114,6 @@ "node": ">=0.10.0" } }, - "node_modules/ssh2": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/ssh2/-/ssh2-1.15.0.tgz", - "integrity": "sha512-C0PHgX4h6lBxYx7hcXwu3QWdh4tg6tZZsTfXcdvc5caW/EMxaB4H9dWsl7qk+F7LAW762hp8VbXOX7x4xUYvEw==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "asn1": "^0.2.6", - "bcrypt-pbkdf": "^1.0.2" - }, - "engines": { - "node": ">=10.16.0" - }, - "optionalDependencies": { - "cpu-features": "~0.0.9", - "nan": "^2.18.0" - } - }, "node_modules/stable-hash-x": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/stable-hash-x/-/stable-hash-x-0.2.0.tgz", @@ -3910,13 +3165,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/style-mod": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz", - "integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==", - "dev": true, - "license": "MIT" - }, "node_modules/tinyglobby": { "version": "0.2.17", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", @@ -4012,13 +3260,6 @@ "dev": true, "license": "0BSD" }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true, - "license": "Unlicense" - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -4142,13 +3383,6 @@ "which-typed-array": "^1.1.2" } }, - "node_modules/w3c-keyname": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", - "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", - "dev": true, - "license": "MIT" - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -4292,9 +3526,9 @@ } }, "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "version": "3.25.67", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.67.tgz", + "integrity": "sha512-idA2YXwpCdqUSKRCACDE6ItZD9TZzy3OZMtpfLoh6oPR47lipysRrJfjzMqFxQ3uJuUPyUeWe1r9vLH33xO/Qw==", "dev": true, "license": "MIT", "funding": { diff --git a/n8n/package.json b/n8n/package.json index d2d3b6e9..04e57256 100644 --- a/n8n/package.json +++ b/n8n/package.json @@ -53,11 +53,11 @@ "eslint-import-resolver-typescript": "4.4.5", "eslint-plugin-import-x": "4.17.1", "eslint-plugin-n8n-nodes-base": "2.0.0", - "n8n-workflow": "2.39.1", + "n8n-workflow": "2.28.4", "prettier": "3.9.6", "typescript": "5.9.2", "typescript-eslint": "8.70.0", - "zod": "3.25.76" + "zod": "3.25.67" }, "peerDependencies": { "n8n-workflow": "*" diff --git a/n8n/test/release.test.cjs b/n8n/test/release.test.cjs index 8c6a9cc6..444a9355 100644 --- a/n8n/test/release.test.cjs +++ b/n8n/test/release.test.cjs @@ -19,11 +19,11 @@ test('0.1.4 release metadata is locked to the audited direct toolchain', () => { 'eslint-import-resolver-typescript': '4.4.5', 'eslint-plugin-import-x': '4.17.1', 'eslint-plugin-n8n-nodes-base': '2.0.0', - 'n8n-workflow': '2.39.1', + 'n8n-workflow': '2.28.4', prettier: '3.9.6', typescript: '5.9.2', 'typescript-eslint': '8.70.0', - zod: '3.25.76', + zod: '3.25.67', }; assert.equal(pkg.version, '0.1.4'); From a26fcfb2f78151ee065cfbf4f1180ca293ae4d94 Mon Sep 17 00:00:00 2001 From: rhein1 Date: Thu, 1 Oct 2026 19:04:14 -0400 Subject: [PATCH 10/15] fix(n8n): qualify audit-clean development workflow fixture --- n8n/TOOLCHAIN_AUDIT.md | 35 +- n8n/package-lock.json | 832 ++------------------------------------ n8n/package.json | 4 +- n8n/test/release.test.cjs | 4 +- 4 files changed, 59 insertions(+), 816 deletions(-) diff --git a/n8n/TOOLCHAIN_AUDIT.md b/n8n/TOOLCHAIN_AUDIT.md index 7c57b54d..6bb90c36 100644 --- a/n8n/TOOLCHAIN_AUDIT.md +++ b/n8n/TOOLCHAIN_AUDIT.md @@ -2,7 +2,7 @@ Original toolchain audit: 2026-09-13 (supersedes 2026-09-01) -Dependency-fixture refresh: 2026-09-25. Rechecked the manifest and lockfile, +Dependency-fixture refresh: 2026-09-30. Rechecked the manifest and lockfile, peer ranges, clean install, tests, lint, build, dependency audits, and package contents. Historical CLI compatibility and Creator Portal acceptance were not revalidated. @@ -17,8 +17,8 @@ revalidated. - Linter: `eslint@9.29.0` - Formatter: `prettier@3.9.6` - Compiler: `typescript@5.9.2` -- Development host fixture: `n8n-workflow@2.39.1` -- Exact workflow peer fixture: `zod@3.25.76` +- Development host fixture: `n8n-workflow@2.28.4` +- Exact workflow peer fixture: `zod@3.25.67` - Minimum consumer Node.js: 20.19 - Locked development and publishing Node.js: 24 - Install mode: committed lockfile plus `npm ci` @@ -30,6 +30,17 @@ publishing workflow. ## Coordinated compatibility decision +The 2.39.1 fixture and available 2.41.1 stable / 2.42.1 beta releases pin +`axios@1.18.0` exactly. Seven newly reported Axios advisories require 1.20.0; +substituting a lock entry cannot satisfy that pin, and overrides remain prohibited. +Use the latest pre-Axios 2.28 patch fixture, 2.28.4, with its exact Zod peer +3.25.67. Its complete development graph audits clean. Clean installation, tests, +lint, build, runtime imports and the offline error boundary pass. All eleven +generated code, declaration and static-asset files are byte-identical to the +2.39.1 build. This changes the development fixture only: package version, +runtime peer, Node consumer floor, node source and audit policy are unchanged. +Requalify a newer fixture once its published dependency graph is patched. + Every available `@n8n/node-cli` line checked from 0.40.0 through the current stable and beta releases pulls an AI/template-only dependency branch through `@n8n/ai-node-sdk`. That branch pins `@langchain/classic@1.0.27` and @@ -84,17 +95,16 @@ The rejected dependency majors remain incoherent with this source candidate: The release-contract test pins the complete supported set so a future isolated major bump cannot look valid after changing only one manifest line. -`n8n-workflow@2.39.1` is the pinned development fixture, not a runtime -constraint. Its exact peer is satisfied by `zod@3.25.76`. The published peer +`n8n-workflow@2.28.4` is the pinned development fixture, not a runtime +constraint. Its exact peer is satisfied by `zod@3.25.67`. The published peer remains `n8n-workflow: "*"`, so host n8n versions are not narrowed. These fixtures keep clean-install build tests deterministic and are not shipped in the package tarball. -The pinned workflow fixture's development graph includes `isolated-vm@7`, -whose declared engine is Node.js 24 or newer. The published community node does -not ship that fixture, so the consumer floor remains Node.js 20.19; repository -validation and trusted publishing use Node.js 24 to satisfy the complete locked -development graph without ignoring engine metadata. +The pinned workflow fixture's development graph includes `isolated-vm@6.2.0`. +The published community node does not ship that fixture, so the consumer floor +remains Node.js 20.19; repository validation and trusted publishing continue to +use Node.js 24 without ignoring engine metadata. ## Security boundary @@ -110,9 +120,8 @@ found 0 vulnerabilities The CLI/AI/LangChain branch and `uuid@10.0.0` are absent from the lockfile. The only resolved `uuid` is patched `uuid@11.1.1` beneath the pinned workflow -fixture. The 2.39.1 development graph resolves `@n8n/utils@1.47.0` and patched -`nanoid@3.3.18`, and adds `quickjs-emscripten@0.32.0` with its `@jitl` QuickJS -WASM packages. These lock entries are development-only. `npm run audit:dev` +fixture. The vulnerable Axios dependency branch is absent from this fixture. +These lock entries are development-only. `npm run audit:dev` rejects any advisory at any severity; there is no development allowlist. The prior `brace-expansion`, `ip-address`, and `undici` findings remain resolved diff --git a/n8n/package-lock.json b/n8n/package-lock.json index c7c6fde4..14af7cb9 100644 --- a/n8n/package-lock.json +++ b/n8n/package-lock.json @@ -15,11 +15,11 @@ "eslint-import-resolver-typescript": "4.4.5", "eslint-plugin-import-x": "4.17.1", "eslint-plugin-n8n-nodes-base": "2.0.0", - "n8n-workflow": "2.39.1", + "n8n-workflow": "2.28.4", "prettier": "3.9.6", "typescript": "5.9.2", "typescript-eslint": "8.70.0", - "zod": "3.25.76" + "zod": "3.25.67" }, "engines": { "node": ">=20.19.0" @@ -28,103 +28,6 @@ "n8n-workflow": "*" } }, - "node_modules/@apm-js-collab/code-transformer": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/@apm-js-collab/code-transformer/-/code-transformer-0.18.1.tgz", - "integrity": "sha512-u1Hb6bHjWtkSpiprwVP6YaHC1DTN4RAU3zYkUDUe7WMnJwdyU1pwTL9dFKiSJB9IiLue/EQovmyx6xhU7FFtAQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/estree": "^1.0.8", - "astring": "^1.9.0", - "esquery": "^1.7.0", - "meriyah": "^6.1.4", - "semifies": "^1.0.0", - "source-map": "^0.6.0" - }, - "bin": { - "code-transformer": "cli.js" - } - }, - "node_modules/@apm-js-collab/code-transformer-bundler-plugins": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/@apm-js-collab/code-transformer-bundler-plugins/-/code-transformer-bundler-plugins-0.7.4.tgz", - "integrity": "sha512-nAfOeZPSUAQvJa1iFT/5oCrTm5YQhMMrfCNthNnaXHZiOQhu1KGuLoIx7HtbAi3wfwaBYLaICPIeenIaEwcXIg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@apm-js-collab/code-transformer": "^0.18.1", - "es-module-lexer": "^2.1.0", - "magic-string": "^0.30.21", - "module-details-from-path": "^1.0.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@apm-js-collab/tracing-hooks": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@apm-js-collab/tracing-hooks/-/tracing-hooks-0.13.0.tgz", - "integrity": "sha512-mTvWz9rnQwx1U3h0XPTHaX7bgfkpipLLTQyjlC2cdhQpQEuoLT0AGzoydeoq2NxfEVv6fWOOETcSbb2nptleyw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@apm-js-collab/code-transformer": "^0.18.0", - "debug": "^4.4.1", - "module-details-from-path": "^1.0.4" - } - }, - "node_modules/@codemirror/autocomplete": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.0.tgz", - "integrity": "sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.17.0", - "@lezer/common": "^1.0.0" - } - }, - "node_modules/@codemirror/language": { - "version": "6.12.4", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.4.tgz", - "integrity": "sha512-1q4PaT+o6PbgpkJt4Q8Fv5XJxTy4FUZ4MWETtyiDw3J0Pyr9E2vqcKL+k9wcvjNTIsauxvE7OfmWj3FRPHQ76A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.23.0", - "@lezer/common": "^1.5.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0", - "style-mod": "^4.0.0" - } - }, - "node_modules/@codemirror/state": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.7.1.tgz", - "integrity": "sha512-9QzNDgE4EYDnAHfrTlR2lwiPciiOymLtwKK+8yHQzCc7GXhAP9xdEbEJFy2IWB1j9UGUl9BsgMmTo/ImA02T7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@marijn/find-cluster-break": "^1.0.0" - } - }, - "node_modules/@codemirror/view": { - "version": "6.43.9", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.43.9.tgz", - "integrity": "sha512-sTuUzTpPMFebRhg6dawChoKKgndIwfjmJgKVxBefPElcU2NwQ6AFroupk0SFqEerQyZOGRfDNnSN8Dw/lMAsXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@codemirror/state": "^6.7.0", - "crelt": "^1.0.6", - "style-mod": "^4.1.0", - "w3c-keyname": "^2.2.4" - } - }, "node_modules/@emnapi/core": { "version": "1.11.3", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.3.tgz", @@ -441,105 +344,10 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@jitl/quickjs-ffi-types": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@jitl/quickjs-ffi-types/-/quickjs-ffi-types-0.32.0.tgz", - "integrity": "sha512-v9T+GQpmk43VDJ7d72sf0Nexhk+ArvtUihW27dy7lqAl0zBObFKtSBBIm5RBjwIhE8VwsPPm9PNuvPvNqLWUEg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jitl/quickjs-wasmfile-debug-asyncify": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@jitl/quickjs-wasmfile-debug-asyncify/-/quickjs-wasmfile-debug-asyncify-0.32.0.tgz", - "integrity": "sha512-EX8zbXwGqCgAE764M+qvkHtyXDi/FUoMBea0JnES7vCM3P7a2+EOZOjGv85wtZ2sJhI1oJ+nekmqpOODFDY+hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jitl/quickjs-ffi-types": "0.32.0" - } - }, - "node_modules/@jitl/quickjs-wasmfile-debug-sync": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@jitl/quickjs-wasmfile-debug-sync/-/quickjs-wasmfile-debug-sync-0.32.0.tgz", - "integrity": "sha512-LeYWrPGC1uNCTBWvibo3ZLJj0CSVNYUXvJpXMCmuQ5Sap2cCACc3uvGvYV4homHHBAzfw5akoTqMMS4YFRtw+Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jitl/quickjs-ffi-types": "0.32.0" - } - }, - "node_modules/@jitl/quickjs-wasmfile-release-asyncify": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@jitl/quickjs-wasmfile-release-asyncify/-/quickjs-wasmfile-release-asyncify-0.32.0.tgz", - "integrity": "sha512-3oSwPfja12ICz4aIblB58cuY8JlEq5Txt8Cut4VLo+LH47QN+mzCnSgnbB03hWzg1LBcc+VyyI9UOag7a1NF+Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jitl/quickjs-ffi-types": "0.32.0" - } - }, - "node_modules/@jitl/quickjs-wasmfile-release-sync": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@jitl/quickjs-wasmfile-release-sync/-/quickjs-wasmfile-release-sync-0.32.0.tgz", - "integrity": "sha512-BKNDI/TPBfGlLNGYpLrhcDGXmIk4xHm4MRAisOBnOzpXVn9HZWsfmMAc9WMBrAHjvvds6HOikKeaOBKdPdpVrg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jitl/quickjs-ffi-types": "0.32.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@lezer/common": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.2.tgz", - "integrity": "sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@lezer/highlight": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz", - "integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@lezer/common": "^1.3.0" - } - }, - "node_modules/@lezer/lr": { - "version": "1.4.10", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.10.tgz", - "integrity": "sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@lezer/common": "^1.0.0" - } - }, - "node_modules/@marijn/find-cluster-break": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.3.tgz", - "integrity": "sha512-FY+MKLBoTsLNJF/eLWaOsXGdz6uh3Iu1axjPf6TUq92IYumcTcXWHoS747JARLkcdlJ/Waiaxc5wQfFO8jC6NA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@n8n/constants": { - "version": "0.38.0", - "resolved": "https://registry.npmjs.org/@n8n/constants/-/constants-0.38.0.tgz", - "integrity": "sha512-xcAHwgKl17ZQS1RFAwjit95dr/AL53WlLqmAcUIFi+A9cTr494aD00RBO/egACTycOY1ZWTst2D1B7jlHpESkg==", - "dev": true, - "license": "SEE LICENSE IN LICENSE.md" - }, "node_modules/@n8n/errors": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@n8n/errors/-/errors-0.13.0.tgz", - "integrity": "sha512-hUZ+ePKp2BzJL40OK1+wTVefJkKLy+mjiBT6KsejkXi1HboYoqHruFqeQZivm5PHhX3CZsHa9ZJy2LGHZrpKCQ==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@n8n/errors/-/errors-0.10.0.tgz", + "integrity": "sha512-Qle4gCsx7qtDRMdie3YkjuXPuo369PP32cR9Svb+INwcjLMxNzmnbJ66jFnOmLn0ntwBccUw1IecJ6axwyTgBQ==", "dev": true, "license": "SEE LICENSE IN LICENSE.md", "dependencies": { @@ -563,48 +371,40 @@ } }, "node_modules/@n8n/expression-runtime": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/@n8n/expression-runtime/-/expression-runtime-0.30.0.tgz", - "integrity": "sha512-mC8yM8+eh0uuN7ZVwvERf/CVUN9hOiaAKG+QtKzfXrFaYSt5AwNXktTsmAdWsLEfH1HjBBXaMc3eMF4IaifPoA==", + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@n8n/expression-runtime/-/expression-runtime-0.19.1.tgz", + "integrity": "sha512-tv86UUD+uBqORBOH70BQaRRXYfatPlygvhk80a4dO2SEubXzIFQxshMb1oA7loEj9ZMeYQesUotvgN57JbPQgA==", "dev": true, "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@n8n/errors": "0.13.0", - "@n8n/tournament": "1.11.0", - "isolated-vm": "^7.0.0", + "@n8n/errors": "0.10.0", + "@n8n/tournament": "1.4.0", + "isolated-vm": "^6.1.2", "jmespath": "0.16.0", "js-base64": "3.7.8", "jssha": "3.3.1", "lodash": "4.18.1", "luxon": "3.7.2", "md5": "2.3.0", - "quickjs-emscripten": "^0.32.0", "title-case": "3.0.3", "transliteration": "2.3.5", - "zod": "3.25.76" + "zod": "3.25.67" } }, "node_modules/@n8n/tournament": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@n8n/tournament/-/tournament-1.11.0.tgz", - "integrity": "sha512-cwu7t9UTTwAPDhGRjY03dRiWeR01wavkj2yWBEN/Rs0og17SvJqfgJ4z7Wgsiha8+iwg+mZ/l+Fv4uEhC5F3FQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@n8n/tournament/-/tournament-1.4.0.tgz", + "integrity": "sha512-llDdmIj3Kdfq2vX/NpLBOUU4kLjhITtIMeJmOSTApAOeAArj1D45ey4D7CFaYcYsPBw6DgF0vxifyskPDlgekw==", "dev": true, "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "ast-types": "^0.16.1", "esprima-next": "^5.8.4", "recast": "^0.22.0" - } - }, - "node_modules/@n8n/utils": { - "version": "1.47.0", - "resolved": "https://registry.npmjs.org/@n8n/utils/-/utils-1.47.0.tgz", - "integrity": "sha512-/wE1a/EEZWqFdJkeEqMp971hDvI2noDSVwQDm1AHFv5oW23h5kVTeG2SySVMWcGZYgnc5bl6Mvcrt35vaSFasg==", - "dev": true, - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@n8n/constants": "0.38.0", - "nanoid": "3.3.18" + }, + "engines": { + "node": ">=20.15", + "pnpm": ">=9.5" } }, "node_modules/@napi-rs/wasm-runtime": { @@ -626,247 +426,6 @@ "@emnapi/runtime": "^1.7.1" } }, - "node_modules/@opentelemetry/api": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", - "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/api-logs": { - "version": "0.220.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.220.0.tgz", - "integrity": "sha512-CmVa4ImJ+ynfrPMNaAXHET6Bhb44SwzmfyVJFq9ni2jgXJR/l7C6gfVFddNmHP+ZOkP9cf4f9DBe68qVLTHc9w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/core": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.10.0.tgz", - "integrity": "sha512-/wNZ8twnEQQA4HoHu22+vcsdru6pWPWxW+7w+FlxT6Id7PE/WIbZmVKkte+PF72e0F2dnImFeHD2syyE1Mw6MQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/instrumentation": { - "version": "0.220.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.220.0.tgz", - "integrity": "sha512-xQx3E2WxP1mDvKzxLxX+CTCtNLa560YJZ3087qYHerl2YmiKpv7AH+dAy7vmx+eVrZ5BwhfWUAVoKOoxCNHcpw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.220.0", - "import-in-the-middle": "^3.0.0", - "require-in-the-middle": "^8.0.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/resources": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.10.0.tgz", - "integrity": "sha512-q6MMm2zhggzsHVNbabYwut+a6nbuQQe3URUoxaojM/8K1IBfwwPzvxIjNi2/lI1TFe+fMHMW9MWhrtDLEXEnkA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.10.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-trace": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace/-/sdk-trace-2.10.0.tgz", - "integrity": "sha512-MfQGq3GRmTh5fM/y+OjaO0vj6+luCB1XO2gfXCalKCfgKw0eHL++sm75DNweC6ohlp+aFvACqeE0fYayqdRaoQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.10.0", - "@opentelemetry/resources": "2.10.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.10.0.tgz", - "integrity": "sha512-GuYQQT7QD2EeO8lcZLRQzcbOyhqAzL+6WWTKTU9mSUBYBazkEDl+VrQcXQhbB08OWM9anD1aHleVadzulpOaUQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.10.0", - "@opentelemetry/resources": "2.10.0", - "@opentelemetry/sdk-trace": "2.10.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.43.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.43.0.tgz", - "integrity": "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/@sentry/conventions": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@sentry/conventions/-/conventions-0.16.0.tgz", - "integrity": "sha512-fO9PLmHdVURcSPUpWCItWAtgKiMwGdJHbovoSEyLplX5sxs2ugvI4CBPTrkkgqhObnZOD0CnWBKDzSVQYBKEyQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - } - }, - "node_modules/@sentry/core": { - "version": "10.70.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.70.0.tgz", - "integrity": "sha512-ozhCTDqg89oB4XmWfAwuHshABpvT7AkRpaPnogopPfMAaI61G1t8EKCJ4W7aum8JSBonlfyjPCyW5oYZFm0KvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sentry/conventions": "^0.16.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@sentry/node": { - "version": "10.70.0", - "resolved": "https://registry.npmjs.org/@sentry/node/-/node-10.70.0.tgz", - "integrity": "sha512-SPOOVxmKTVIEtqvOKkQT163e/pOwucjS7OPsCHyRs8sFR4nfBNu0EThplyqnvqd5BWBMTPH6WTBQfo+QWHV+HA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@opentelemetry/api": "^1.9.1", - "@opentelemetry/instrumentation": "^0.220.0", - "@opentelemetry/sdk-trace-base": "^2.9.0", - "@sentry/conventions": "^0.16.0", - "@sentry/core": "10.70.0", - "@sentry/node-core": "10.70.0", - "@sentry/opentelemetry": "10.70.0", - "@sentry/server-utils": "10.70.0", - "import-in-the-middle": "^3.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@sentry/node-core": { - "version": "10.70.0", - "resolved": "https://registry.npmjs.org/@sentry/node-core/-/node-core-10.70.0.tgz", - "integrity": "sha512-oPOEVVNxv5WHtckx2i06Wi9FLWyvOg/1DUeX732jZ4iqT2nupINaMH4nF4f4kSvUThFnxkFSRQxwqOxgzMKhKA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sentry/conventions": "^0.16.0", - "@sentry/core": "10.70.0", - "@sentry/opentelemetry": "10.70.0", - "import-in-the-middle": "^3.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.9.0", - "@opentelemetry/core": "^1.30.1 || ^2.1.0", - "@opentelemetry/exporter-trace-otlp-http": ">=0.57.0 <1", - "@opentelemetry/instrumentation": ">=0.57.1 <1", - "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0" - }, - "peerDependenciesMeta": { - "@opentelemetry/api": { - "optional": true - }, - "@opentelemetry/core": { - "optional": true - }, - "@opentelemetry/exporter-trace-otlp-http": { - "optional": true - }, - "@opentelemetry/instrumentation": { - "optional": true - }, - "@opentelemetry/sdk-trace-base": { - "optional": true - } - } - }, - "node_modules/@sentry/opentelemetry": { - "version": "10.70.0", - "resolved": "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-10.70.0.tgz", - "integrity": "sha512-UNV/2tqypcUK6FDzerAsFJn1Km/c4VZCYkUZDNbnV5S0cwAq2BYKMo4M5vovaLDBQlxA+Wk9ovbxi5wYjjl9fw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sentry/conventions": "^0.16.0", - "@sentry/core": "10.70.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.9.0", - "@opentelemetry/core": "^1.30.1 || ^2.1.0", - "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0" - } - }, - "node_modules/@sentry/server-utils": { - "version": "10.70.0", - "resolved": "https://registry.npmjs.org/@sentry/server-utils/-/server-utils-10.70.0.tgz", - "integrity": "sha512-rzegZjMFFgCp3o+N8+XU13rfSvz4B+f8rU0ijBGrQcHdMNyfsFDTu1UTm262JofmrV2u+s+D0u0vFTnqtOGkbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@apm-js-collab/code-transformer-bundler-plugins": "^0.7.3", - "@apm-js-collab/tracing-hooks": "^0.13.0", - "@sentry/conventions": "^0.16.0", - "@sentry/core": "10.70.0", - "meriyah": "^6.1.4" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/@tybys/wasm-util": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", @@ -1545,16 +1104,6 @@ "dev": true, "license": "Python-2.0" }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, "node_modules/assert": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", @@ -1582,16 +1131,6 @@ "node": ">=4" } }, - "node_modules/astring": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", - "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", - "dev": true, - "license": "MIT", - "bin": { - "astring": "bin/astring" - } - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -1615,56 +1154,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/axios": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.18.0.tgz", - "integrity": "sha512-E32NzpYKp++W7XRe52rHiXV2ehxmh3wbdgO7MHeFM+vqxLBYHzt0ElkiImtOBxtOmyp0yoC8C6uESVV84Y2/hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.16.0", - "form-data": "^4.0.5", - "https-proxy-agent": "^5.0.1", - "proxy-from-env": "^2.1.0" - } - }, - "node_modules/axios/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/axios/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/axios/node_modules/proxy-from-env": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", - "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, "node_modules/balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", @@ -1675,16 +1164,6 @@ "node": "18 || 20 || >=22" } }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, "node_modules/brace-expansion": { "version": "5.0.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", @@ -1698,16 +1177,6 @@ "node": "20 || >=22" } }, - "node_modules/buildcheck": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.7.tgz", - "integrity": "sha512-lHblz4ahamxpTmnsk+MNTRWsjYKv965MwOrSJyeD588rR3Jcu7swE+0wN5F+PbL5cjgu/9ObkhfzEPuofEMwLA==", - "dev": true, - "optional": true, - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/call-bind": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", @@ -1819,13 +1288,6 @@ "node": "*" } }, - "node_modules/cjs-module-lexer": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.1.tgz", - "integrity": "sha512-Ca8swihM+/4yKecYHY52kgJd300hi2lADU/a1RxNTRe+RJ9jvqQlESpbz9DnG9mowez8qwXHB8qYdIUw9e+F5Q==", - "dev": true, - "license": "MIT" - }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -1891,28 +1353,6 @@ "dev": true, "license": "MIT" }, - "node_modules/cpu-features": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.10.tgz", - "integrity": "sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "dependencies": { - "buildcheck": "~0.0.6", - "nan": "^2.19.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/crelt": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.7.tgz", - "integrity": "sha512-aK6BbWfhf4U/wCcLHKPJl/xa6VkVstRaPywWtMKGwuOLc/wZTyQYuoxgvZnNsBvv7Kg3YTBQYYBCggcviQczuA==", - "dev": true, - "license": "MIT" - }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -2051,13 +1491,6 @@ "node": ">= 0.4" } }, - "node_modules/es-module-lexer": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", - "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", - "dev": true, - "license": "MIT" - }, "node_modules/es-object-atoms": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", @@ -2559,27 +1992,6 @@ "dev": true, "license": "ISC" }, - "node_modules/follow-redirects": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", - "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, "node_modules/for-each": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", @@ -2826,21 +2238,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-in-the-middle": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-3.3.3.tgz", - "integrity": "sha512-AiohS3H80sXO6owEltjGX+glb7qXaDhBoJb9XcQVH4UI207xu/bDLUcadVKp7Qe576reg9yr/PXZjV5qx8gfbA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "cjs-module-lexer": "^2.2.0", - "es-module-lexer": "^2.2.0", - "module-details-from-path": "^1.0.4" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -3028,9 +2425,9 @@ "license": "ISC" }, "node_modules/isolated-vm": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/isolated-vm/-/isolated-vm-7.0.1.tgz", - "integrity": "sha512-nBCQ1hXEaYKYJ79wwfhaF44ITOJC30Hw0wPEsFeNsdD3hdeKK7FW1SGMQYBUA+qasvkqdOazI+iBuq0lcbN/aw==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/isolated-vm/-/isolated-vm-6.2.0.tgz", + "integrity": "sha512-UuSlxSHWt2QuJ5WvBhzlIJx2VVZN/a44SqBbEZFKNdvuSyhOvhmyDo8SQ+njVbhnh/njoL/aW0bUTiFYlpweGQ==", "dev": true, "hasInstallScript": true, "license": "ISC", @@ -3038,7 +2435,7 @@ "node-gyp-build": "^4.8.4" }, "engines": { - "node": ">=24.0.0" + "node": ">=22.0.0" } }, "node_modules/jmespath": { @@ -3088,13 +2485,6 @@ "dev": true, "license": "MIT" }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true, - "license": "(AFL-2.1 OR BSD-3-Clause)" - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -3203,16 +2593,6 @@ "node": ">=12" } }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -3235,16 +2615,6 @@ "is-buffer": "~1.1.6" } }, - "node_modules/meriyah": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/meriyah/-/meriyah-6.1.4.tgz", - "integrity": "sha512-Sz8FzjzI0kN13GK/6MVEsVzMZEPvOhnmmI1lU5+/1cGOiK3QUahntrNNtdVeihrO7t9JpoH75iMNXg6R6uWflQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -3284,13 +2654,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/module-details-from-path": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz", - "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==", - "dev": true, - "license": "MIT" - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -3299,42 +2662,34 @@ "license": "MIT" }, "node_modules/n8n-workflow": { - "version": "2.39.1", - "resolved": "https://registry.npmjs.org/n8n-workflow/-/n8n-workflow-2.39.1.tgz", - "integrity": "sha512-nN6Wctmwr8O/e1mxmjXA58PbAtbmHQf0tYFHExRW4ZvmgwpowJ/VZBxEaCia2HwtzippmdfCj8ckTQbQnibvRw==", + "version": "2.28.4", + "resolved": "https://registry.npmjs.org/n8n-workflow/-/n8n-workflow-2.28.4.tgz", + "integrity": "sha512-wNWCEvk5eBxnp5p2y/6FpMsA5t6XZVBm8HIV/u1XiUX/p91UtdBvQW0f8tTr4B79G1aeKl/l8cSroit/WFuK6A==", "dev": true, "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@codemirror/autocomplete": "6.20.0", - "@n8n/constants": "0.38.0", - "@n8n/errors": "0.13.0", - "@n8n/expression-runtime": "0.30.0", - "@n8n/tournament": "1.11.0", - "@n8n/utils": "1.47.0", - "@sentry/core": "10.70.0", - "@sentry/node": "10.70.0", + "@n8n/errors": "0.10.0", + "@n8n/expression-runtime": "0.19.1", + "@n8n/tournament": "1.4.0", "ast-types": "0.16.1", - "axios": "1.18.0", "callsites": "3.1.0", "esprima-next": "5.8.4", "form-data": "4.0.6", "jmespath": "0.16.0", "js-base64": "3.7.8", - "json-schema": "0.4.0", "jsonrepair": "3.13.2", "jssha": "3.3.1", "lodash": "4.18.1", "luxon": "3.7.2", "md5": "2.3.0", "recast": "0.22.0", - "ssh2": "1.15.0", "title-case": "3.0.3", "transliteration": "2.3.5", "uuid": "11.1.1", "xml2js": "0.6.2" }, "peerDependencies": { - "zod": "3.25.76" + "zod": "3.25.67" } }, "node_modules/n8n-workflow/node_modules/uuid": { @@ -3351,33 +2706,6 @@ "uuid": "dist/esm/bin/uuid" } }, - "node_modules/nan": { - "version": "2.28.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.28.0.tgz", - "integrity": "sha512-fTsDz99OTq2sVePhGdp4qQhggZFtKr64ZNVyVajRKtMOkJxYekplBh577PiJB12v/D3s2E5cGtOI45LWp6rnLQ==", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/nanoid": { - "version": "3.3.18", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", - "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/napi-postinstall": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", @@ -3622,33 +2950,6 @@ "node": ">=6" } }, - "node_modules/quickjs-emscripten": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/quickjs-emscripten/-/quickjs-emscripten-0.32.0.tgz", - "integrity": "sha512-So0Sqw869y/S2oE3Nuc0uT3Dhqgvsj8FSrwBdsuTosVsG8ME5/OcudU1GxsrIFdFABgy17GHnTVO9TYV/bLQcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jitl/quickjs-wasmfile-debug-asyncify": "0.32.0", - "@jitl/quickjs-wasmfile-debug-sync": "0.32.0", - "@jitl/quickjs-wasmfile-release-asyncify": "0.32.0", - "@jitl/quickjs-wasmfile-release-sync": "0.32.0", - "quickjs-emscripten-core": "0.32.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/quickjs-emscripten-core": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/quickjs-emscripten-core/-/quickjs-emscripten-core-0.32.0.tgz", - "integrity": "sha512-QFnPfjFey8EqknSrSxe1hZrf1/8z7/6s1QzGOmKo6++02r7QRRX7ZoyNaZh7JuVjWsVW87KnQrbZqnHkOAzUyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jitl/quickjs-ffi-types": "0.32.0" - } - }, "node_modules/recast": { "version": "0.22.0", "resolved": "https://registry.npmjs.org/recast/-/recast-0.22.0.tgz", @@ -3689,20 +2990,6 @@ "node": ">=0.10.0" } }, - "node_modules/require-in-the-middle": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-8.0.1.tgz", - "integrity": "sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.5", - "module-details-from-path": "^1.0.3" - }, - "engines": { - "node": ">=9.3.0 || >=8.10.0 <9.0.0" - } - }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -3741,13 +3028,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "license": "MIT" - }, "node_modules/sax": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz", @@ -3758,13 +3038,6 @@ "node": ">=11.0.0" } }, - "node_modules/semifies": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semifies/-/semifies-1.0.0.tgz", - "integrity": "sha512-xXR3KGeoxTNWPD4aBvL5NUpMTT7WMANr3EWnaS190QVkY52lqqcVRD7Q05UVbBhiWDGWMlJEUam9m7uFFGVScw==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/semver": { "version": "7.8.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", @@ -3841,24 +3114,6 @@ "node": ">=0.10.0" } }, - "node_modules/ssh2": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/ssh2/-/ssh2-1.15.0.tgz", - "integrity": "sha512-C0PHgX4h6lBxYx7hcXwu3QWdh4tg6tZZsTfXcdvc5caW/EMxaB4H9dWsl7qk+F7LAW762hp8VbXOX7x4xUYvEw==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "asn1": "^0.2.6", - "bcrypt-pbkdf": "^1.0.2" - }, - "engines": { - "node": ">=10.16.0" - }, - "optionalDependencies": { - "cpu-features": "~0.0.9", - "nan": "^2.18.0" - } - }, "node_modules/stable-hash-x": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/stable-hash-x/-/stable-hash-x-0.2.0.tgz", @@ -3910,13 +3165,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/style-mod": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz", - "integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==", - "dev": true, - "license": "MIT" - }, "node_modules/tinyglobby": { "version": "0.2.17", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", @@ -4012,13 +3260,6 @@ "dev": true, "license": "0BSD" }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true, - "license": "Unlicense" - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -4142,13 +3383,6 @@ "which-typed-array": "^1.1.2" } }, - "node_modules/w3c-keyname": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", - "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", - "dev": true, - "license": "MIT" - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -4292,9 +3526,9 @@ } }, "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "version": "3.25.67", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.67.tgz", + "integrity": "sha512-idA2YXwpCdqUSKRCACDE6ItZD9TZzy3OZMtpfLoh6oPR47lipysRrJfjzMqFxQ3uJuUPyUeWe1r9vLH33xO/Qw==", "dev": true, "license": "MIT", "funding": { diff --git a/n8n/package.json b/n8n/package.json index d2d3b6e9..04e57256 100644 --- a/n8n/package.json +++ b/n8n/package.json @@ -53,11 +53,11 @@ "eslint-import-resolver-typescript": "4.4.5", "eslint-plugin-import-x": "4.17.1", "eslint-plugin-n8n-nodes-base": "2.0.0", - "n8n-workflow": "2.39.1", + "n8n-workflow": "2.28.4", "prettier": "3.9.6", "typescript": "5.9.2", "typescript-eslint": "8.70.0", - "zod": "3.25.76" + "zod": "3.25.67" }, "peerDependencies": { "n8n-workflow": "*" diff --git a/n8n/test/release.test.cjs b/n8n/test/release.test.cjs index 8c6a9cc6..444a9355 100644 --- a/n8n/test/release.test.cjs +++ b/n8n/test/release.test.cjs @@ -19,11 +19,11 @@ test('0.1.4 release metadata is locked to the audited direct toolchain', () => { 'eslint-import-resolver-typescript': '4.4.5', 'eslint-plugin-import-x': '4.17.1', 'eslint-plugin-n8n-nodes-base': '2.0.0', - 'n8n-workflow': '2.39.1', + 'n8n-workflow': '2.28.4', prettier: '3.9.6', typescript: '5.9.2', 'typescript-eslint': '8.70.0', - zod: '3.25.76', + zod: '3.25.67', }; assert.equal(pkg.version, '0.1.4'); From c0679c56deb33035197515acd681786cc5617f86 Mon Sep 17 00:00:00 2001 From: rhein1 Date: Thu, 1 Oct 2026 19:05:48 -0400 Subject: [PATCH 11/15] fix(n8n): avoid Windows audit subprocess path parsing --- n8n/scripts/audit-dev-dependencies.cjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/n8n/scripts/audit-dev-dependencies.cjs b/n8n/scripts/audit-dev-dependencies.cjs index c3a422b7..23b651a6 100644 --- a/n8n/scripts/audit-dev-dependencies.cjs +++ b/n8n/scripts/audit-dev-dependencies.cjs @@ -29,7 +29,7 @@ function main() { : ['audit', '--json', '--audit-level=low']; const result = spawnSync(command, args, { encoding: 'utf8', - shell: process.platform === 'win32', + shell: !npmCli && process.platform === 'win32', }); if (result.error) throw result.error; if (![0, 1].includes(result.status)) { From a95729e8f944b5cb3b187a16db015ce71f86c11e Mon Sep 17 00:00:00 2001 From: rhein1 Date: Thu, 1 Oct 2026 19:20:40 -0400 Subject: [PATCH 12/15] chore: renew bounded MatrAIx inventory review --- integrations.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations.json b/integrations.json index f3cb13fc..c876a69f 100644 --- a/integrations.json +++ b/integrations.json @@ -443,7 +443,7 @@ "reason": "The exact upstream source lock, closed representation contract, no-spend target policy, and deterministic fixture replay pass, but no live MatrAIx provider run or independent external compatibility review has occurred.", "owner": "repository-maintainers", "tracking_ref": "https://github.com/rhein1/agoragentic-integrations/pull/320", - "review_by": "2026-09-30", + "review_by": "2026-10-08", "published": false, "external_compatibility_verified": false, "ready_for_manifest": false, From a1283ee9a0740f9314220d84d5694c4b450911b2 Mon Sep 17 00:00:00 2001 From: rhein1 Date: Thu, 1 Oct 2026 20:43:08 -0400 Subject: [PATCH 13/15] fix(deps): align hosted MCP bundle with reviewed dependency closure --- risk-fork-hosted-mcp/THIRD_PARTY_NOTICES.txt | 2 +- risk-fork-hosted-mcp/dist/runtime/index.mjs | 13 ++--- risk-fork-hosted-mcp/integrity-manifest.json | 16 +++--- risk-fork-hosted-mcp/package-lock.json | 12 ++--- .../test/package-artifact.test.mjs | 50 +++++++++++++++++++ 5 files changed, 72 insertions(+), 21 deletions(-) diff --git a/risk-fork-hosted-mcp/THIRD_PARTY_NOTICES.txt b/risk-fork-hosted-mcp/THIRD_PARTY_NOTICES.txt index a6870c9c..5fd1bd1b 100644 --- a/risk-fork-hosted-mcp/THIRD_PARTY_NOTICES.txt +++ b/risk-fork-hosted-mcp/THIRD_PARTY_NOTICES.txt @@ -548,7 +548,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ======================================================================== -fast-uri@3.1.7 +fast-uri@3.1.8 Declared license: BSD-3-Clause Notice source: risk-fork-hosted-mcp/node_modules/fast-uri/LICENSE Notice source method: standalone_license_file diff --git a/risk-fork-hosted-mcp/dist/runtime/index.mjs b/risk-fork-hosted-mcp/dist/runtime/index.mjs index b9528971..c87447a0 100644 --- a/risk-fork-hosted-mcp/dist/runtime/index.mjs +++ b/risk-fork-hosted-mcp/dist/runtime/index.mjs @@ -48050,13 +48050,14 @@ var require_fast_uri = __commonJS({ if (!malformedIPLiteral) { malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP2); } - if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) { - if (uri.indexOf("%") !== -1) { - if (parsed.host !== void 0 && !malformedIPLiteral) { - const host = isIP2 ? parsed.host : normalizePercentEncoding(parsed.host, true); - parsed.host = reescapeHostDelimiters(host, isIP2); - } + if (uri.indexOf("%") !== -1 && parsed.host !== void 0 && !malformedIPLiteral) { + let host = isIP2 ? parsed.host : normalizePercentEncoding(parsed.host, true); + if (!isIP2) { + host = normalizePercentEncoding(host.toLowerCase()); } + parsed.host = reescapeHostDelimiters(host, isIP2); + } + if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) { if (parsed.path) { parsed.path = normalizePathEncoding(parsed.path); } diff --git a/risk-fork-hosted-mcp/integrity-manifest.json b/risk-fork-hosted-mcp/integrity-manifest.json index 2c9f49cb..27745032 100644 --- a/risk-fork-hosted-mcp/integrity-manifest.json +++ b/risk-fork-hosted-mcp/integrity-manifest.json @@ -1191,8 +1191,8 @@ { "path": "risk-fork-hosted-mcp/node_modules/fast-uri/index.js", "source": "workspace_dependency", - "bytes": 22061, - "sha256": "sha256:e82d3e55d954483e4927f9740bc3113a24d19ef5a73c7962d8a93c499fc982ff" + "bytes": 22264, + "sha256": "sha256:62876e5094b43ba2ba90374613dab4576fd337063dad20b4b07cc5e3a7e2303b" }, { "path": "risk-fork-hosted-mcp/node_modules/fast-uri/lib/schemes.js", @@ -1210,7 +1210,7 @@ "path": "risk-fork-hosted-mcp/node_modules/fast-uri/package.json", "source": "workspace_dependency", "bytes": 1983, - "sha256": "sha256:e634f3848a2c6c7e1cdc28b119b16e072e10dada8a3ca3f175a2372d0dd83360" + "sha256": "sha256:30cad05aad3d3596513706451dbfc7e0422f9c1d00f2903ecc34580327d54bc7" }, { "path": "risk-fork-hosted-mcp/node_modules/json-schema-traverse/LICENSE", @@ -2380,7 +2380,7 @@ "third_party_notices": { "path": "THIRD_PARTY_NOTICES.txt", "bytes": 56885, - "sha256": "sha256:88c6a3301b747237128435917d181c66aa2568234f40947531a0b0de0d3477fd", + "sha256": "sha256:84761a19dbe9d442127b5dd3d83f35831a756f888589ae6fc5132b31af733855", "sources": [ { "package": "@modelcontextprotocol/core", @@ -2439,7 +2439,7 @@ }, { "package": "fast-uri", - "version": "3.1.7", + "version": "3.1.8", "declared_license": "BSD-3-Clause", "method": "standalone_license_file", "path": "risk-fork-hosted-mcp/node_modules/fast-uri/LICENSE", @@ -2628,8 +2628,8 @@ }, "artifact": { "path": "dist/runtime/index.mjs", - "bytes": 3111081, - "sha256": "sha256:c5e9814e13b84d5489527adeaac27e4d47363acec706cef3bcbe17f53e06dcc6" + "bytes": 3111138, + "sha256": "sha256:db99484dfa89944be8edaf8e5e52c0b0ce6ca620fc5455c509d245ae2ffd3a09" }, "packaged_assets": [ { @@ -2653,7 +2653,7 @@ { "path": "THIRD_PARTY_NOTICES.txt", "bytes": 56885, - "sha256": "sha256:88c6a3301b747237128435917d181c66aa2568234f40947531a0b0de0d3477fd" + "sha256": "sha256:84761a19dbe9d442127b5dd3d83f35831a756f888589ae6fc5132b31af733855" }, { "path": "e2b-context/risk-fork/e2b-template/bin/boot-guard.mjs", diff --git a/risk-fork-hosted-mcp/package-lock.json b/risk-fork-hosted-mcp/package-lock.json index 1d61d55d..e5c7d962 100644 --- a/risk-fork-hosted-mcp/package-lock.json +++ b/risk-fork-hosted-mcp/package-lock.json @@ -1049,9 +1049,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.7.tgz", - "integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", + "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", "dev": true, "funding": [ { @@ -1252,9 +1252,9 @@ "license": "ISC" }, "node_modules/ip-address": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.5.0.tgz", - "integrity": "sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g==", + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.3.tgz", + "integrity": "sha512-A1kdq/tSb5QjvKvAMgIoEvDBIgL7qaqVP/jkvSwYYRZ9iEzvPpopxp2wQfu3SuZRHtpHNxMn8Fs0bS+gf5Xmwg==", "dev": true, "license": "MIT", "engines": { diff --git a/risk-fork-hosted-mcp/test/package-artifact.test.mjs b/risk-fork-hosted-mcp/test/package-artifact.test.mjs index 3179c584..32228a2c 100644 --- a/risk-fork-hosted-mcp/test/package-artifact.test.mjs +++ b/risk-fork-hosted-mcp/test/package-artifact.test.mjs @@ -44,6 +44,7 @@ const HOSTED_FIXTURE_COPIES = Object.freeze([ ['transaction-assurance/src', 'transaction-assurance/src'], ['risk-fork-hosted-mcp/integrity-manifest.json', 'risk-fork-hosted-mcp/integrity-manifest.json'], ['risk-fork-hosted-mcp/node_modules', 'risk-fork-hosted-mcp/node_modules'], + ['risk-fork-hosted-mcp/package-lock.json', 'risk-fork-hosted-mcp/package-lock.json'], ['risk-fork-hosted-mcp/package.json', 'risk-fork-hosted-mcp/package.json'], ['risk-fork-hosted-mcp/scripts', 'risk-fork-hosted-mcp/scripts'], ['risk-fork-hosted-mcp/src', 'risk-fork-hosted-mcp/src'], @@ -249,6 +250,34 @@ async function assertGeneratedHostedOutputsUnchanged(expectedSnapshot) { } } +async function assertHostedFastUriClosure(root) { + const hostedRoot = path.join(root, 'risk-fork-hosted-mcp'); + const lock = JSON.parse(await readFile(path.join(hostedRoot, 'package-lock.json'), 'utf8')); + const mcpPackage = JSON.parse(await readFile(path.join(root, 'mcp', 'package.json'), 'utf8')); + const advertisedVersion = mcpPackage.overrides?.['fast-uri']; + assert.equal(typeof advertisedVersion, 'string'); + + const lockRecord = lock.packages?.['node_modules/fast-uri']; + assert.equal(lockRecord?.version, advertisedVersion, 'hosted lock must satisfy the MCP fast-uri override'); + const installedPackagePath = path.join(hostedRoot, 'node_modules', 'fast-uri', 'package.json'); + const installedPackageBytes = await readFile(installedPackagePath); + const installedPackage = JSON.parse(installedPackageBytes); + assert.equal(installedPackage.version, lockRecord.version, 'installed fast-uri must satisfy the hosted lock'); + + const manifest = JSON.parse(await readFile(path.join(hostedRoot, 'integrity-manifest.json'), 'utf8')); + const notice = manifest.third_party_notices.sources.find((source) => source.package === 'fast-uri'); + assert.equal(notice?.version, installedPackage.version, 'attested fast-uri notice must match the installed package'); + const inputPath = 'risk-fork-hosted-mcp/node_modules/fast-uri/package.json'; + const input = manifest.inputs.find((record) => record.path === inputPath); + assert.ok(input, 'attested fast-uri package metadata must be an integrity input'); + assert.equal(input.bytes, installedPackageBytes.byteLength); + assert.equal(input.sha256, sha256(installedPackageBytes)); + + const bundle = (await readFile(path.join(hostedRoot, 'dist', 'runtime', 'index.mjs'))).toString('utf8'); + const advertisedEntry = `${JSON.stringify('fast-uri')}: ${JSON.stringify(advertisedVersion)}`; + assert.ok(bundle.includes(advertisedEntry), 'bundle must retain the MCP fast-uri advertisement'); +} + const committedGeneratedOutputSnapshot = await snapshotGeneratedHostedOutputs(packageRoot); test('package contract is private, exact-version, and has no mandatory runtime dependencies', async () => { @@ -539,6 +568,27 @@ test('build is deterministic and records exact source and artifact integrity', a run(process.execPath, ['scripts/verify-integrity.mjs', '--source']); }); +test('hosted lock, bundle advertisement, and attested fast-uri records stay aligned', async () => { + const fixture = await createHostedFixture('risk-fork-hosted-dependency-closure-'); + try { + run(process.execPath, ['scripts/build.mjs'], { cwd: fixture.packageRoot }); + await assertHostedFastUriClosure(fixture.repositoryRoot); + + const lockPath = path.join(fixture.packageRoot, 'package-lock.json'); + const staleLock = JSON.parse(await readFile(lockPath, 'utf8')); + staleLock.packages['node_modules/fast-uri'].version = '3.1.7'; + staleLock.packages['node_modules/fast-uri'].resolved = 'https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.7.tgz'; + staleLock.packages['node_modules/fast-uri'].integrity = 'sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg=='; + await writeFile(lockPath, `${JSON.stringify(staleLock, null, 2)}\n`, 'utf8'); + await assert.rejects( + assertHostedFastUriClosure(fixture.repositoryRoot), + /hosted lock must satisfy the MCP fast-uri override/, + ); + } finally { + await cleanupTemporary(fixture.temporary); + } +}); + test('standalone license discovery preserves actual casing and fails closed on ambiguity or non-files', async () => { const entry = (name, type = 'file') => ({ name, From 5f5758afc4b4d0165dee3761ab6f81c10b008bba Mon Sep 17 00:00:00 2001 From: Rhein1 / Agoragentic <140637602+rhein1@users.noreply.github.com> Date: Fri, 2 Oct 2026 00:15:28 -0400 Subject: [PATCH 14/15] fix(governance): preserve nested receipt and exception identities --- .github/workflows/validate.yml | 15 ++ sdk/node/README.md | 10 ++ sdk/node/local-governance.js | 39 +++- sdk/python/README.md | 12 ++ sdk/python/src/agoragentic/governance.py | 90 ++++++---- sdk/python/tests/test_governance_lifecycle.py | 45 +++-- sdk/python/tests/test_receipt_identity.py | 170 ++++++++++++++++++ test/governance-receipt-identity.test.mjs | 84 +++++++++ 8 files changed, 410 insertions(+), 55 deletions(-) create mode 100644 sdk/python/tests/test_receipt_identity.py create mode 100644 test/governance-receipt-identity.test.mjs diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 6376f9e2..a7bb9f0f 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -62,6 +62,21 @@ permissions: contents: read jobs: + python-sdk-compat: + runs-on: ubuntu-22.04 + strategy: + matrix: + python: ['3.8', '3.14'] + steps: + - uses: actions/checkout@v7.0.1 + - uses: actions/setup-python@v7.0.0 + with: + python-version: ${{ matrix.python }} + - name: Test dependency-free Python SDK at minimum and current versions + env: + PYTHONPATH: sdk/python/src + run: python -m unittest discover -s sdk/python/tests -p 'test_*.py' + validate: runs-on: ubuntu-latest steps: diff --git a/sdk/node/README.md b/sdk/node/README.md index cfa13e51..01cd35b1 100644 --- a/sdk/node/README.md +++ b/sdk/node/README.md @@ -102,6 +102,16 @@ with the original receipt in both `error.response.receipt` and and evidence exceptions retain their identity and use the `agoragenticReceipt` access convention when the thrown value can accept properties. `receipts: false` disables persistence and supplies `null` to receipt callbacks. +Receipt callbacks receive a deep copy, so their mutations cannot change the +canonical receipt retained on notification errors. Nested failures retain the +inner `agoragenticReceipt`; successfully persisted enclosing action receipts are +listed separately in `agoragenticEnclosingReceipts`, from inner to outer. +If recording an approval, tool, or evidence failure itself fails, the original +exception still propagates. Where metadata attachment is possible, +`agoragenticReceiptError` records only `code: "receipt_persistence_failed"`, +`action`, `phase`, and `outcome`; it does not claim a durable receipt or include +storage paths or error messages. Frozen, primitive, or hostile thrown values may +not expose metadata; any successfully persisted receipts remain on disk. These wrappers do not retry, resume, roll back effects, or provide restart-safe execution. ## Hosted Router Model diff --git a/sdk/node/local-governance.js b/sdk/node/local-governance.js index 0237f8ba..659a3be0 100644 --- a/sdk/node/local-governance.js +++ b/sdk/node/local-governance.js @@ -235,12 +235,21 @@ function govern(tool, options = {}) { startedAt, finishedAt: nowIso(options), outcome, evidence: { argument_count: args.length, ...evidence }, })); + const recordFailure = (error, decision, phase, outcome) => { + try { + attachReceipt(error, record(decision, outcome, { error_code: safeErrorCode(error) })); + } catch { + // The original failure takes precedence; do not claim a durable receipt. + attachMetadata(error, 'agoragenticReceiptError', { + code: 'receipt_persistence_failed', phase, action, outcome, + }); + } + }; if (initial.decision === 'ask' && !approved && typeof options.approve === 'function') { try { approved = await options.approve({ action, argument_count: args.length }) === true; } catch (err) { - const receipt = record(initial, 'approval_failed', { error_code: safeErrorCode(err) }); - attachReceipt(err, receipt); + recordFailure(err, initial, 'approval', 'approval_failed'); throw err; } } @@ -263,8 +272,7 @@ function govern(tool, options = {}) { try { result = await tool(...args); } catch (err) { - const receipt = record(decision, 'failed', { error_code: safeErrorCode(err) }); - attachReceipt(err, receipt); + recordFailure(err, decision, 'tool', 'failed'); throw err; } let evidence; @@ -273,14 +281,14 @@ function govern(tool, options = {}) { ? summarizeEvidence(await options.evidence(result)) : summarizeEvidence(result); } catch (err) { - const receipt = record(decision, 'completed_evidence_failed', { error_code: safeErrorCode(err) }); - attachReceipt(err, receipt); + recordFailure(err, decision, 'evidence', 'completed_evidence_failed'); throw err; } const receipt = record(decision, 'completed', { result: evidence }); if (typeof options.onReceipt === 'function') { try { - await options.onReceipt(receipt); + // Callback-owned copy: retained evidence must match the persisted JSON. + await options.onReceipt(receipt === null ? null : JSON.parse(JSON.stringify(receipt))); } catch (err) { const error = governanceError('receipt_callback_failed', 'Receipt callback failed after the tool completed.', 1, { receipt }); error.agoragenticReceipt = receipt; @@ -293,8 +301,21 @@ function govern(tool, options = {}) { } function attachReceipt(error, receipt) { - // JavaScript permits primitive and frozen throws; preserve the original failure. - try { error.agoragenticReceipt = receipt; } catch { /* receipt remains on disk */ } + try { + const existing = Object.getOwnPropertyDescriptor(error, 'agoragenticReceipt'); + if (!existing || existing.value == null) { + attachMetadata(error, 'agoragenticReceipt', receipt); + } else if (receipt !== null) { + const enclosing = Object.getOwnPropertyDescriptor(error, 'agoragenticEnclosingReceipts')?.value; + attachMetadata(error, 'agoragenticEnclosingReceipts', [...(Array.isArray(enclosing) ? enclosing : []), receipt]); + } + } catch { /* hostile/primitive/frozen errors retain identity; receipts remain on disk */ } +} + +function attachMetadata(error, key, value) { + try { + Object.defineProperty(error, key, { value, writable: true, configurable: true, enumerable: true }); + } catch { /* diagnostic metadata must never replace the original failure */ } } async function runGovernedCommand(executable, args = [], options = {}) { diff --git a/sdk/python/README.md b/sdk/python/README.md index 0b43c0fc..fe4ad689 100644 --- a/sdk/python/README.md +++ b/sdk/python/README.md @@ -58,11 +58,23 @@ If receipt persistence fails while handling cancellation, the original `CancelledError` still propagates and the task remains cancelled. `agoragentic_receipt` is `None` unless a nested governed call already attached its own durable receipt, which is retained on outer persistence failure. +It is also retained when outer persistence succeeds: enclosing action receipts +are listed separately in `agoragentic_enclosing_receipts`, from inner to outer. +Nested ordinary failures preserve `GovernanceError.receipt` and its +`agoragentic_receipt` alias in the same way. Receipt callbacks receive deep copies, +so callback mutation cannot change the canonical receipt retained on errors. `agoragentic_receipt_error` contains only `code: "receipt_persistence_failed"`, the failed action identity, the phase, and the attempted outcome. An inner action's retained receipt does not prove persistence for the failed outer action. That marker is not a durable receipt or proof that a partial file was removed; it contains no filesystem path or persistence-exception message. +The same bounded marker accompanies ordinary failure-recording errors while +preserving tool exceptions and existing callback `GovernanceError` cause chains. +All exception metadata is best-effort: a subclass that rejects attribute writes +still propagates unchanged, and successfully persisted receipts remain on disk. +These identity guarantees apply at the governed coroutine boundary. Python 3.8 +may replace `CancelledError` when it crosses a cancelled `Task` boundary; catch +inside that task to inspect metadata, or reconcile the persisted receipts. ## Hosted Router Model diff --git a/sdk/python/src/agoragentic/governance.py b/sdk/python/src/agoragentic/governance.py index 42e4de46..6d06c7d2 100644 --- a/sdk/python/src/agoragentic/governance.py +++ b/sdk/python/src/agoragentic/governance.py @@ -8,6 +8,7 @@ from __future__ import annotations import asyncio +import copy import functools import inspect import json @@ -193,8 +194,8 @@ def wrapped(*args: Any, **kwargs: Any) -> Any: error = exc else: error = GovernanceError("approval_failed", "Approval callback failed.") - receipt = _write_pre_execution_failure(context, request, error.code) - error.receipt = receipt + _record_failure(error, context, "approval", "approval_failed", + lambda: _write_pre_execution_failure(context, request, error.code)) raise error from exc decision = evaluate_policy(context["policy"], context["action"], approved=resolved_approval) @@ -202,11 +203,8 @@ def wrapped(*args: Any, **kwargs: Any) -> Any: try: result = tool(*args, **kwargs) except Exception as exc: - receipt = _write_failed_receipt(context, decision, request, exc) - try: - setattr(exc, "agoragentic_receipt", receipt) - except (AttributeError, TypeError): - pass + _record_failure(exc, context, "tool", "failed", + lambda: _write_failed_receipt(context, decision, request, exc)) raise if inspect.isawaitable(result): if hasattr(result, "close"): @@ -215,7 +213,8 @@ def wrapped(*args: Any, **kwargs: Any) -> Any: "tool_result_async", "A synchronous governed tool returned an awaitable; declare the tool with async def.", ) - error.receipt = _write_evidence_failure(context, decision, request, error) + _record_failure(error, context, "evidence", "completed_evidence_failed", + lambda: _write_evidence_failure(context, decision, request, error)) raise error try: evidence_result = options["evidence"](result) if options["evidence"] else result @@ -231,7 +230,8 @@ def wrapped(*args: Any, **kwargs: Any) -> Any: "evidence_failed", "Post-action evidence capture failed after the tool completed.", ) - error.receipt = _write_evidence_failure(context, decision, request, error) + _record_failure(error, context, "evidence", "completed_evidence_failed", + lambda: _write_evidence_failure(context, decision, request, error)) raise error from exc receipt = _write_receipt( context, @@ -266,8 +266,8 @@ async def wrapped(*args: Any, **kwargs: Any) -> Any: raise except Exception as exc: error = GovernanceError("approval_failed", "Approval callback failed.") - receipt = _write_pre_execution_failure(context, request, error.code) - error.receipt = receipt + _record_failure(error, context, "approval", "approval_failed", + lambda: _write_pre_execution_failure(context, request, error.code)) raise error from exc decision = evaluate_policy(context["policy"], context["action"], approved=resolved_approval) @@ -279,11 +279,8 @@ async def wrapped(*args: Any, **kwargs: Any) -> Any: phase="tool", outcome="cancelled_effect_uncertain") raise except Exception as exc: - receipt = _write_failed_receipt(context, decision, request, exc) - try: - setattr(exc, "agoragentic_receipt", receipt) - except (AttributeError, TypeError): - pass + _record_failure(exc, context, "tool", "failed", + lambda: _write_failed_receipt(context, decision, request, exc)) raise try: evidence_result = options["evidence"](result) if options["evidence"] else result @@ -299,7 +296,8 @@ async def wrapped(*args: Any, **kwargs: Any) -> Any: "evidence_failed", "Post-action evidence capture failed after the tool completed.", ) - error.receipt = _write_evidence_failure(context, decision, request, exc) + _record_failure(error, context, "evidence", "completed_evidence_failed", + lambda: _write_evidence_failure(context, decision, request, exc)) raise error from exc receipt = _write_receipt( context, @@ -309,11 +307,11 @@ async def wrapped(*args: Any, **kwargs: Any) -> Any: ) if options["on_receipt"]: try: - callback_result = options["on_receipt"](receipt) + callback_result = options["on_receipt"](copy.deepcopy(receipt)) if inspect.isawaitable(callback_result): await callback_result except asyncio.CancelledError as exc: - exc.agoragentic_receipt = receipt + _attach_receipt(exc, receipt) raise except Exception as exc: raise GovernanceError( @@ -335,22 +333,54 @@ def _record_cancellation( phase: str, outcome: str, ) -> None: - # Persistence must never replace cancellation or imply a durable receipt - # when the write fails (including a partially written file). - # A nested governed call may already have attached a durable receipt for - # its own action. Keep that receipt if this outer persistence attempt fails. - if not hasattr(cancellation, "agoragentic_receipt"): - cancellation.agoragentic_receipt = None - try: - cancellation.agoragentic_receipt = _write_receipt( + _record_failure(cancellation, context, phase, outcome, + lambda: _write_receipt( context, decision, outcome=outcome, evidence=dict(request, error_code="CancelledError"), ) + ) + + +def _attach_metadata(error: BaseException, name: str, value: Any) -> None: + try: + setattr(error, name, value) + except BaseException: + # User exception subclasses may reject metadata with any exception. + # Only this diagnostic operation is guarded, never the governed work. + pass + + +def _attach_receipt(error: BaseException, receipt: Optional[Dict[str, Any]]) -> None: + try: + metadata = object.__getattribute__(error, "__dict__") + existing = metadata.get("agoragentic_receipt") + if existing is None and isinstance(error, GovernanceError): + existing = metadata.get("receipt") + if existing is None: + _attach_metadata(error, "agoragentic_receipt", receipt) + if isinstance(error, GovernanceError): + _attach_metadata(error, "receipt", receipt) + else: + _attach_metadata(error, "agoragentic_receipt", existing) + if receipt is not None: + enclosing = metadata.get("agoragentic_enclosing_receipts", []) + _attach_metadata(error, "agoragentic_enclosing_receipts", [*enclosing, receipt]) + except BaseException: + pass # Preserve hostile cancellation/error subclasses and durable disk evidence. + + +def _record_failure(error: BaseException, context: Dict[str, Any], phase: str, + outcome: str, write: Callable[[], Optional[Dict[str, Any]]]) -> None: + try: + receipt = write() except Exception: - cancellation.agoragentic_receipt_error = { + _attach_receipt(error, None) + _attach_metadata(error, "agoragentic_receipt_error", { "code": "receipt_persistence_failed", "phase": phase, "action": context["action"], "outcome": outcome, - } + }) + else: + _attach_receipt(error, receipt) def _prepare_invocation(options: Dict[str, Any]) -> Dict[str, Any]: @@ -548,7 +578,7 @@ def _notify_sync( if callback is None: return try: - result = callback(receipt) + result = callback(copy.deepcopy(receipt)) if inspect.isawaitable(result): if hasattr(result, "close"): result.close() diff --git a/sdk/python/tests/test_governance_lifecycle.py b/sdk/python/tests/test_governance_lifecycle.py index c83d1cb6..96e60c2c 100644 --- a/sdk/python/tests/test_governance_lifecycle.py +++ b/sdk/python/tests/test_governance_lifecycle.py @@ -7,6 +7,16 @@ from agoragentic.governance import GovernanceError, create_default_policy, govern +async def observe_cancellation(awaitable, observed): + # Python 3.8 Task.result/await may create a fresh CancelledError. Observe the + # wrapper boundary inside the task to test SDK identity and metadata. + try: + return await awaitable + except asyncio.CancelledError as exc: + observed.append(exc) + raise + + class CancellationTests(unittest.IsolatedAsyncioTestCase): async def test_outer_persistence_failure_retains_inner_notification_receipt(self): with tempfile.TemporaryDirectory() as root: @@ -38,8 +48,9 @@ async def notify(receipt): async def outer_tool(): await inner() - task = asyncio.create_task(govern(outer_tool, action="outer.run", policy=policy, - cwd=outer_root)()) + observed = [] + task = asyncio.create_task(observe_cancellation(govern(outer_tool, action="outer.run", policy=policy, + cwd=outer_root)(), observed)) await asyncio.wait_for(entered.wait(), 2) directory = outer_root / ".agoragentic" / "receipts" directory.rmdir() @@ -48,13 +59,13 @@ async def outer_tool(): with self.assertRaises(asyncio.CancelledError) as raised: await task self.assertTrue(task.cancelled()) - self.assertIs(raised.exception, cancellations[0]) - self.assertIs(raised.exception.agoragentic_receipt, delivered[0]) + self.assertIs(observed[0], cancellations[0]) + self.assertEqual(observed[0].agoragentic_receipt, delivered[0]) self.assertEqual(delivered[0]["action"], "inner.write") persisted = json.loads((inner_root / delivered[0]["path"]).read_text()) self.assertEqual(persisted["receipt_id"], delivered[0]["receipt_id"]) self.assertEqual(persisted["outcome"], "completed") - self.assertEqual(raised.exception.agoragentic_receipt_error, { + self.assertEqual(observed[0].agoragentic_receipt_error, { "code": "receipt_persistence_failed", "phase": "tool", "action": "outer.run", "outcome": "cancelled_effect_uncertain", }) @@ -89,19 +100,20 @@ async def evidence(result): await pause("evidence") return result - task = asyncio.create_task(govern(tool, action="file.write", policy=policy, - cwd=root, approve=approve, evidence=evidence)()) + observed = [] + task = asyncio.create_task(observe_cancellation(govern(tool, action="file.write", policy=policy, + cwd=root, approve=approve, evidence=evidence)(), observed)) await asyncio.wait_for(entered.wait(), 2) directory = Path(root, ".agoragentic", "receipts") directory.rmdir() # Verified empty fixture directory, inside TemporaryDirectory. directory.write_text("private-obstruction") - task.cancel("private-cancellation") + task.cancel() with self.assertRaises(asyncio.CancelledError) as raised: await task self.assertTrue(task.cancelled()) - self.assertIs(raised.exception, cancellations[0]) - self.assertIsNone(raised.exception.agoragentic_receipt) - self.assertEqual(raised.exception.agoragentic_receipt_error, { + self.assertIs(observed[0], cancellations[0]) + self.assertIsNone(observed[0].agoragentic_receipt) + self.assertEqual(observed[0].agoragentic_receipt_error, { "code": "receipt_persistence_failed", "phase": phase, "action": "file.write", "outcome": {"approval": "approval_failed", "tool": "cancelled_effect_uncertain", "evidence": "completed_evidence_failed"}[phase], @@ -109,7 +121,7 @@ async def evidence(result): self.assertEqual(Path(root, "effect.txt").exists(), phase != "approval") self.assertEqual(directory.read_text(), "private-obstruction") self.assertEqual(list(Path(root).rglob("*.json")), []) - marker = json.dumps(raised.exception.agoragentic_receipt_error) + marker = json.dumps(observed[0].agoragentic_receipt_error) self.assertNotIn("private-", marker) self.assertNotIn(root, marker) @@ -235,16 +247,17 @@ async def notify(receipt): wrapped = govern(tool, action="file.write", policy=policy, cwd=root, receipts=enabled, approve=approve, evidence=evidence, on_receipt=notify) - task = asyncio.create_task(wrapped("private-payload-and-error")) + observed = [] + task = asyncio.create_task(observe_cancellation(wrapped("private-payload-and-error"), observed)) await asyncio.wait_for(entered.wait(), 2) - task.cancel("private-payload-and-error") + task.cancel() with self.assertRaises(asyncio.CancelledError) as raised: await task self.assertTrue(task.cancelled()) files = list(Path(root, ".agoragentic/receipts").glob("*.json")) if not enabled: self.assertEqual(files, []) - self.assertIsNone(raised.exception.agoragentic_receipt) + self.assertIsNone(observed[0].agoragentic_receipt) self.assertFalse(Path(root, ".agoragentic").exists()) continue self.assertEqual(len(files), 1) @@ -256,7 +269,7 @@ async def notify(receipt): }[phase]) self.assertEqual(Path(root, "effect.txt").exists(), phase != "approval") self.assertNotIn("private-payload-and-error", raw) - self.assertEqual(raised.exception.agoragentic_receipt["receipt_id"], receipt["receipt_id"]) + self.assertEqual(observed[0].agoragentic_receipt["receipt_id"], receipt["receipt_id"]) for flag in ("provider_execution", "payment", "settlement"): self.assertFalse(receipt["proof_scope"][flag]) if phase == "notification": diff --git a/sdk/python/tests/test_receipt_identity.py b/sdk/python/tests/test_receipt_identity.py new file mode 100644 index 00000000..1aa4c94e --- /dev/null +++ b/sdk/python/tests/test_receipt_identity.py @@ -0,0 +1,170 @@ +import asyncio +import json +import tempfile +import unittest +from pathlib import Path + +from agoragentic.governance import GovernanceError, create_default_policy, govern + + +class HostileCancellation(asyncio.CancelledError): + def __setattr__(self, name, value): + if name.startswith('agoragentic_'): + raise RuntimeError('private-metadata-error') + super().__setattr__(name, value) + + @property + def agoragentic_receipt(self): + raise RuntimeError('private-property-error') + + +def policy(): + result = create_default_policy() + result['default_decision'] = 'allow' + return result + + +class ReceiptIdentityTests(unittest.IsolatedAsyncioTestCase): + async def test_original_failures_survive_storage_failure_sync_and_async(self): + for asynchronous in (False, True): + for phase in ('approval', 'tool', 'evidence'): + with self.subTest(asynchronous=asynchronous, phase=phase), tempfile.TemporaryDirectory() as root: + p = policy() + p['default_decision'] = 'ask' + original = RuntimeError('private-original') + effects = [] + + def fail(at): + if at == phase: + directory = Path(root, '.agoragentic/receipts') + directory.rmdir() + directory.write_text('private-obstruction') + raise original + + def tool(): + effects.append(1) + fail('tool') + return 'private-result' + + async def async_tool(): + return tool() + + wrapped = govern(async_tool if asynchronous else tool, action='file.write', + policy=p, cwd=root, approve=lambda _: fail('approval') or True, + evidence=lambda _: fail('evidence')) + with self.assertRaises(RuntimeError) as raised: + if asynchronous: + await wrapped() + else: + wrapped() + error = raised.exception + self.assertIs(error if phase == 'tool' else error.__cause__, original) + self.assertIsNone(error.agoragentic_receipt) + self.assertEqual(error.agoragentic_receipt_error, { + 'code': 'receipt_persistence_failed', 'phase': phase, 'action': 'file.write', + 'outcome': {'approval': 'approval_failed', 'tool': 'failed', + 'evidence': 'completed_evidence_failed'}[phase]}) + self.assertEqual(len(effects), int(phase != 'approval')) + self.assertEqual(list(Path(root).rglob('*.json')), []) + + async def test_hostile_cancellation_preserved_in_all_phases(self): + for phase in ('approval', 'tool', 'evidence', 'notification'): + for obstruct in (False, True): + with self.subTest(phase=phase, obstruct=obstruct), tempfile.TemporaryDirectory() as root: + p = policy() + p['default_decision'] = 'ask' + original = HostileCancellation('private-cancel') + effects = [] + + async def fail(at): + if phase == at: + if obstruct and phase != 'notification': + directory = Path(root, '.agoragentic/receipts') + directory.rmdir() + directory.write_text('private-obstruction') + raise original + + async def approve(_): + await fail('approval') + return True + + async def tool(): + effects.append(1) + await fail('tool') + return 'private-result' + + async def evidence(_): + await fail('evidence') + + async def notify(_): + await fail('notification') + + with self.assertRaises(asyncio.CancelledError) as raised: + await govern(tool, action='file.write', policy=p, cwd=root, + approve=approve, evidence=evidence, on_receipt=notify)() + self.assertIs(raised.exception, original) + self.assertEqual(len(effects), int(phase != 'approval')) + receipts = [json.loads(f.read_text()) for f in Path(root).rglob('*.json')] + self.assertEqual(len(receipts), int(not obstruct or phase == 'notification')) + if receipts: + self.assertEqual(receipts[0]['outcome'], {'approval': 'approval_failed', + 'tool': 'cancelled_effect_uncertain', 'evidence': 'completed_evidence_failed', + 'notification': 'completed'}[phase]) + self.assertNotIn('private-', json.dumps(receipts)) + + async def test_nested_cancellation_keeps_inner_receipt_with_successful_outer_write(self): + with tempfile.TemporaryDirectory() as root: + original = asyncio.CancelledError('private-cancel') + + async def tool(): + return 'done' + + async def notify(receipt): + receipt['receipt_id'] = 'nonexistent' + receipt['proof_scope']['payment'] = True + raise original + + inner = govern(tool, action='inner.run', policy=policy(), cwd=root, on_receipt=notify) + outer = govern(inner, action='outer.run', policy=policy(), cwd=root) + with self.assertRaises(asyncio.CancelledError) as raised: + await outer() + self.assertIs(raised.exception, original) + receipts = [json.loads(f.read_text()) for f in Path(root).rglob('*.json')] + self.assertEqual(len(receipts), 2) + self.assertEqual(original.agoragentic_receipt['action'], 'inner.run') + self.assertFalse(original.agoragentic_receipt['proof_scope']['payment']) + enclosing = original.agoragentic_enclosing_receipts + self.assertEqual([r['action'] for r in enclosing], ['outer.run']) + self.assertEqual(enclosing[0]['outcome'], 'cancelled_effect_uncertain') + self.assertEqual({r['receipt_id'] for r in receipts}, + {original.agoragentic_receipt['receipt_id'], enclosing[0]['receipt_id']}) + + async def test_nested_notification_errors_and_mutation_sync_and_async(self): + for asynchronous in (False, True): + with self.subTest(asynchronous=asynchronous), tempfile.TemporaryDirectory() as root: + def notify(receipt): + receipt['receipt_id'] = 'nonexistent' + receipt['action'] = 'wrong.action' + receipt['proof_scope']['payment'] = True + raise RuntimeError('private-callback') + + async def async_tool(): + return 'done' + + inner = govern(async_tool if asynchronous else lambda: 'done', action='inner.run', + policy=policy(), cwd=root, on_receipt=notify) + outer = govern(inner, action='outer.run', policy=policy(), cwd=root) + with self.assertRaises(GovernanceError) as raised: + if asynchronous: + await outer() + else: + outer() + error = raised.exception + self.assertEqual(error.code, 'receipt_callback_failed') + self.assertEqual(error.receipt['action'], 'inner.run') + self.assertIs(error.agoragentic_receipt, error.receipt) + self.assertFalse(error.receipt['proof_scope']['payment']) + self.assertEqual([r['action'] for r in error.agoragentic_enclosing_receipts], ['outer.run']) + receipts = [json.loads(f.read_text()) for f in Path(root).rglob('*.json')] + self.assertEqual(len(receipts), 2) + self.assertIn(error.receipt['receipt_id'], [r['receipt_id'] for r in receipts]) diff --git a/test/governance-receipt-identity.test.mjs b/test/governance-receipt-identity.test.mjs new file mode 100644 index 00000000..b960280e --- /dev/null +++ b/test/governance-receipt-identity.test.mjs @@ -0,0 +1,84 @@ +import assert from 'node:assert/strict'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; +import { govern, createDefaultPolicy } from '../sdk/node/local-governance.mjs'; + +function fixture(t) { + const cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'receipt-identity-')); + t.after(() => fs.rmSync(cwd, { recursive: true, force: true })); + const policy = createDefaultPolicy(); + policy.default_decision = 'allow'; + const directory = path.join(cwd, '.agoragentic/receipts'); + return { cwd, policy, directory, read: () => fs.readdirSync(directory).map(name => + JSON.parse(fs.readFileSync(path.join(directory, name), 'utf8'))) }; +} + +for (const phase of ['approval', 'tool', 'evidence']) { + test(`${phase} original error survives failed receipt persistence`, async t => { + const f = fixture(t); + if (phase === 'approval') f.policy.default_decision = 'ask'; + const original = new Error('private-original'); + let effects = 0; + const fail = () => { + fs.rmdirSync(f.directory); + fs.writeFileSync(f.directory, 'private-obstruction'); + throw original; + }; + const wrapped = govern(() => { effects++; if (phase === 'tool') fail(); return 'private-result'; }, { + ...f, action: 'file.write', approve: fail, evidence: phase === 'evidence' ? fail : undefined, + }); + await assert.rejects(wrapped(), error => { + assert.equal(error, original); + assert.equal(error.agoragenticReceipt, undefined); + assert.deepEqual(error.agoragenticReceiptError, { code: 'receipt_persistence_failed', phase, + action: 'file.write', outcome: { approval: 'approval_failed', tool: 'failed', evidence: 'completed_evidence_failed' }[phase] }); + return true; + }); + assert.equal(effects, phase === 'approval' ? 0 : 1); + assert.equal(fs.readFileSync(f.directory, 'utf8'), 'private-obstruction'); + }); +} + +for (const enabled of [true, false]) { + test(`nested notification failure retains inner identity (outer receipts ${enabled})`, async t => { + const f = fixture(t); + let innerError; + const inner = govern(() => 'done', { ...f, action: 'inner.run', onReceipt() { throw new Error('private'); } }); + const middle = govern(async () => { try { await inner(); } catch (e) { innerError = e; throw e; } }, + { ...f, action: 'middle.run', receipts: enabled }); + const outer = govern(middle, { ...f, action: 'outer.run' }); + await assert.rejects(outer(), error => { + assert.equal(error, innerError); + assert.equal(error.agoragenticReceipt, error.response.receipt); + assert.equal(error.agoragenticReceipt.action, 'inner.run'); + assert.deepEqual(error.agoragenticEnclosingReceipts.map(r => r.action), enabled ? ['middle.run', 'outer.run'] : ['outer.run']); + const receipts = f.read(); + assert.equal(receipts.length, enabled ? 3 : 2); + for (const receipt of [error.agoragenticReceipt, ...error.agoragenticEnclosingReceipts]) { + assert.equal(receipts.find(r => r.receipt_id === receipt.receipt_id).action, receipt.action); + } + return true; + }); + }); +} + +test('notification mutation cannot alter canonical persisted receipt references', async t => { + const f = fixture(t); + const wrapped = govern(() => 'private-result', { ...f, action: 'file.write', onReceipt(receipt) { + receipt.receipt_id = 'nonexistent'; + receipt.action = 'wrong.action'; + receipt.proof_scope.payment = true; + throw new Error('private-callback'); + } }); + await assert.rejects(wrapped(), error => { + const receipts = f.read(); + assert.equal(receipts.length, 1); + assert.equal(error.agoragenticReceipt, error.response.receipt); + assert.equal(error.agoragenticReceipt.receipt_id, receipts[0].receipt_id); + assert.equal(error.agoragenticReceipt.action, 'file.write'); + assert.equal(error.agoragenticReceipt.proof_scope.payment, false); + return true; + }); +}); From f65143fcd8336bc3fe0a926e486dc34adc9b1d60 Mon Sep 17 00:00:00 2001 From: Rhein1 / Agoragentic <140637602+rhein1@users.noreply.github.com> Date: Fri, 2 Oct 2026 00:25:16 -0400 Subject: [PATCH 15/15] ci: run governed receipt identity regressions --- .github/workflows/validate.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index a7bb9f0f..f4c0ce41 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -148,6 +148,7 @@ jobs: node --test test/sdk-public-source.test.mjs node --test test/local-governance-cli.test.mjs node --test test/governance-lifecycle.test.mjs + node --test test/governance-receipt-identity.test.mjs node --check sdk/node/index.js node --check sdk/node/index.mjs node --check sdk/agent-os-cli/cli.js