From c5b4fbf2388dfeeffa29cb6a93028b5d67f98908 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Thu, 27 Nov 2025 10:34:11 +0100 Subject: [PATCH 01/86] Update node-forge, npm-registry-fetch and make-fetch-happen --- package-lock.json | 816 +++++++------------------------ packages/safe-chain/package.json | 6 +- 2 files changed, 167 insertions(+), 655 deletions(-) diff --git a/package-lock.json b/package-lock.json index 60bd1bf..caf51f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,120 +23,62 @@ "resolved": "test/e2e", "link": true }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/fs-minipass": { + "node_modules/@isaacs/balanced-match": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", - "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", - "license": "ISC", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "license": "MIT", "dependencies": { - "minipass": "^7.0.4" + "@isaacs/balanced-match": "^4.0.1" }, "engines": { - "node": ">=18.0.0" + "node": "20 || >=22" } }, "node_modules/@npmcli/agent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-3.0.0.tgz", - "integrity": "sha512-S79NdEgDQd/NGCay6TCoVzXSj74skRZIKJcpJjC5lOq34SZzyI6MqtiiWoiVWoVrTcGjNeC4ipbh1VIHlpfF5Q==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-4.0.0.tgz", + "integrity": "sha512-kAQTcEN9E8ERLVg5AsGwLNoFb+oEG6engbqAU2P43gD4JEIkNGMHdVQ096FsOAAYpZPB0RSt0zgInKIAS1l5QA==", "license": "ISC", "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.1", - "lru-cache": "^10.0.1", + "lru-cache": "^11.2.1", "socks-proxy-agent": "^8.0.3" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/@npmcli/fs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-4.0.0.tgz", - "integrity": "sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-5.0.0.tgz", + "integrity": "sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og==", "license": "ISC", "dependencies": { "semver": "^7.3.5" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/@npmcli/redact": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-3.2.2.tgz", - "integrity": "sha512-7VmYAmk4csGv08QzrDKScdzn11jHPFGyqJW39FyPgPuAp3zIaUmuCo1yxw9aGs+NEJuTGQ9Gwqpt93vtJubucg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-4.0.0.tgz", + "integrity": "sha512-gOBg5YHMfZy+TfHArfVogwgfBeQnKbbGo3pSUyK/gSI0AVu+pEiDVcKlQb0D8Mg1LNRZILZ6XG8I5dJ4KuAd9Q==", "license": "ISC", "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/@oxlint/darwin-arm64": { @@ -243,16 +185,6 @@ "win32" ] }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, "node_modules/@types/ini": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/@types/ini/-/ini-4.1.1.tgz", @@ -357,71 +289,32 @@ "node": ">= 14" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" - }, - "node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/cacache": { - "version": "19.0.1", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-19.0.1.tgz", - "integrity": "sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ==", + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-20.0.3.tgz", + "integrity": "sha512-3pUp4e8hv07k1QlijZu6Kn7c9+ZpWWk4j3F8N3xPuCExULobqJydKYOTj1FTq58srkJsXvO7LbGAH4C0ZU3WGw==", "license": "ISC", "dependencies": { - "@npmcli/fs": "^4.0.0", + "@npmcli/fs": "^5.0.0", "fs-minipass": "^3.0.0", - "glob": "^10.2.2", - "lru-cache": "^10.0.1", + "glob": "^13.0.0", + "lru-cache": "^11.1.0", "minipass": "^7.0.3", "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^7.0.2", - "ssri": "^12.0.0", - "tar": "^7.4.3", - "unique-filename": "^4.0.0" + "ssri": "^13.0.0", + "unique-filename": "^5.0.0" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/call-bind-apply-helpers": { @@ -457,33 +350,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chownr": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", - "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" - }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -496,20 +362,6 @@ "node": ">= 0.8" } }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/debug": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", @@ -550,18 +402,6 @@ "node": ">= 0.4" } }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "license": "MIT" - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, "node_modules/encoding": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", @@ -572,19 +412,6 @@ "iconv-lite": "^0.6.2" } }, - "node_modules/encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "license": "MIT", - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/err-code": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", @@ -636,22 +463,6 @@ "node": ">= 0.4" } }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/form-data": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", @@ -727,35 +538,17 @@ } }, "node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "license": "ISC", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.0.tgz", + "integrity": "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==", + "license": "BlueOak-1.0.0", "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", + "minimatch": "^10.1.1", "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" + "path-scurry": "^2.0.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -813,15 +606,15 @@ } }, "node_modules/hosted-git-info": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", - "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.2.tgz", + "integrity": "sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==", "license": "ISC", "dependencies": { - "lru-cache": "^10.0.1" + "lru-cache": "^11.1.0" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/http-cache-semantics": { @@ -856,6 +649,19 @@ "node": ">= 14" } }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -875,54 +681,14 @@ } }, "node_modules/ip-address": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", - "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", + "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", "license": "MIT", - "dependencies": { - "jsbn": "1.1.0", - "sprintf-js": "^1.1.3" - }, "engines": { "node": ">= 12" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/jsbn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "license": "MIT" - }, "node_modules/jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", @@ -933,31 +699,34 @@ "license": "MIT" }, "node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "license": "ISC" + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", + "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", + "license": "ISC", + "engines": { + "node": "20 || >=22" + } }, "node_modules/make-fetch-happen": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-14.0.3.tgz", - "integrity": "sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ==", + "version": "15.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-15.0.3.tgz", + "integrity": "sha512-iyyEpDty1mwW3dGlYXAJqC/azFn5PPvgKVwXayOGBSmKLxhKZ9fg4qIan2ePpp1vJIwfFiO34LAPZgq9SZW9Aw==", "license": "ISC", "dependencies": { - "@npmcli/agent": "^3.0.0", - "cacache": "^19.0.1", + "@npmcli/agent": "^4.0.0", + "cacache": "^20.0.1", "http-cache-semantics": "^4.1.1", "minipass": "^7.0.2", - "minipass-fetch": "^4.0.0", + "minipass-fetch": "^5.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^1.0.0", - "proc-log": "^5.0.0", + "proc-log": "^6.0.0", "promise-retry": "^2.0.1", - "ssri": "^12.0.0" + "ssri": "^13.0.0" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/math-intrinsics": { @@ -990,6 +759,21 @@ "node": ">= 0.6" } }, + "node_modules/minimatch": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", + "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/minipass": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", @@ -1012,9 +796,9 @@ } }, "node_modules/minipass-fetch": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-4.0.1.tgz", - "integrity": "sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-5.0.0.tgz", + "integrity": "sha512-fiCdUALipqgPWrOVTz9fw0XhcazULXOSU6ie40DDbX1F49p1dBrSRBuswndTx1x3vEb/g0FT7vC4c4C2u/mh3A==", "license": "MIT", "dependencies": { "minipass": "^7.0.3", @@ -1022,7 +806,7 @@ "minizlib": "^3.0.1" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" }, "optionalDependencies": { "encoding": "^0.1.13" @@ -1052,12 +836,6 @@ "node": ">=8" } }, - "node_modules/minipass-flush/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, "node_modules/minipass-pipeline": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", @@ -1082,12 +860,6 @@ "node": ">=8" } }, - "node_modules/minipass-pipeline/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, "node_modules/minipass-sized": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", @@ -1112,16 +884,10 @@ "node": ">=8" } }, - "node_modules/minipass-sized/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, "node_modules/minizlib": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", - "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", "license": "MIT", "dependencies": { "minipass": "^7.1.2" @@ -1130,21 +896,6 @@ "node": ">= 18" } }, - "node_modules/mkdirp": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", - "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", - "license": "MIT", - "bin": { - "mkdirp": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -1167,9 +918,9 @@ } }, "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.2.tgz", + "integrity": "sha512-6xKiQ+cph9KImrRh0VsjH2d8/GXA4FIMlgU4B757iI1ApvcyA9VlouP0yZJha01V+huImO+kKMU7ih+2+E14fw==", "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { "node": ">= 6.13.0" @@ -1186,37 +937,37 @@ } }, "node_modules/npm-package-arg": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-12.0.2.tgz", - "integrity": "sha512-f1NpFjNI9O4VbKMOlA5QoBq/vSQPORHcTZ2feJpFkTHJ9eQkdlmZEKSjcAhxTGInC7RlEyScT9ui67NaOsjFWA==", + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-13.0.2.tgz", + "integrity": "sha512-IciCE3SY3uE84Ld8WZU23gAPPV9rIYod4F+rc+vJ7h7cwAJt9Vk6TVsK60ry7Uj3SRS3bqRRIGuTp9YVlk6WNA==", "license": "ISC", "dependencies": { - "hosted-git-info": "^8.0.0", - "proc-log": "^5.0.0", + "hosted-git-info": "^9.0.0", + "proc-log": "^6.0.0", "semver": "^7.3.5", - "validate-npm-package-name": "^6.0.0" + "validate-npm-package-name": "^7.0.0" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm-registry-fetch": { - "version": "18.0.2", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-18.0.2.tgz", - "integrity": "sha512-LeVMZBBVy+oQb5R6FDV9OlJCcWDU+al10oKpe+nsvcHnG24Z3uM3SvJYKfGJlfGjVU8v9liejCrUR/M5HO5NEQ==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-19.1.1.tgz", + "integrity": "sha512-TakBap6OM1w0H73VZVDf44iFXsOS3h+L4wVMXmbWOQroZgFhMch0juN6XSzBNlD965yIKvWg2dfu7NSiaYLxtw==", "license": "ISC", "dependencies": { - "@npmcli/redact": "^3.0.0", + "@npmcli/redact": "^4.0.0", "jsonparse": "^1.3.1", - "make-fetch-happen": "^14.0.0", + "make-fetch-happen": "^15.0.0", "minipass": "^7.0.2", - "minipass-fetch": "^4.0.0", + "minipass-fetch": "^5.0.0", "minizlib": "^3.0.1", - "npm-package-arg": "^12.0.0", - "proc-log": "^5.0.0" + "npm-package-arg": "^13.0.0", + "proc-log": "^6.0.0" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/oxlint": { @@ -1254,9 +1005,9 @@ } }, "node_modules/p-map": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.3.tgz", - "integrity": "sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", "license": "MIT", "engines": { "node": ">=18" @@ -1265,44 +1016,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "license": "BlueOak-1.0.0" - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", + "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==", "license": "BlueOak-1.0.0", "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" }, "engines": { - "node": ">=16 || 14 >=14.18" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/proc-log": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-5.0.0.tgz", - "integrity": "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", + "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==", "license": "ISC", "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/promise-retry": { @@ -1346,39 +1082,6 @@ "node": ">=10" } }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -1390,12 +1093,12 @@ } }, "node_modules/socks": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz", - "integrity": "sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==", + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", + "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", "license": "MIT", "dependencies": { - "ip-address": "^9.0.5", + "ip-address": "^10.0.1", "smart-buffer": "^4.2.0" }, "engines": { @@ -1417,93 +1120,16 @@ "node": ">= 14" } }, - "node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "license": "BSD-3-Clause" - }, "node_modules/ssri": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-12.0.0.tgz", - "integrity": "sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-13.0.0.tgz", + "integrity": "sha512-yizwGBpbCn4YomB2lzhZqrHLJoqFGXihNbib3ozhqF/cIp5ue+xSmOQrjNasEE62hFxsCcg/V/z23t4n8jMEng==", "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tar": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", - "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", - "license": "ISC", - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.0.1", - "mkdirp": "^3.0.1", - "yallist": "^5.0.0" - }, - "engines": { - "node": ">=18" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/typescript": { @@ -1526,158 +1152,43 @@ "dev": true }, "node_modules/unique-filename": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-4.0.0.tgz", - "integrity": "sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-5.0.0.tgz", + "integrity": "sha512-2RaJTAvAb4owyjllTfXzFClJ7WsGxlykkPvCr9pA//LD9goVq+m4PPAeBgNodGZ7nSrntT/auWpJ6Y5IFXcfjg==", "license": "ISC", "dependencies": { - "unique-slug": "^5.0.0" + "unique-slug": "^6.0.0" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/unique-slug": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-5.0.0.tgz", - "integrity": "sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-6.0.0.tgz", + "integrity": "sha512-4Lup7Ezn8W3d52/xBhZBVdx323ckxa7DEvd9kPQHppTkLoJXw6ltrBCyj5pnrxj0qKDxYMJ56CoxNuFCscdTiw==", "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/validate-npm-package-name": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-6.0.0.tgz", - "integrity": "sha512-d7KLgL1LD3U3fgnvWEY1cQXoO/q6EQ1BSz48Sa149V/5zVTAbgmZIpyI8TRi6U9/JNyeYLlTKsEMPtLC27RFUg==", - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.0.tgz", + "integrity": "sha512-bwVk/OK+Qu108aJcMAEiU4yavHUI7aN20TgZNBj9MR2iU1zPUl1Z1Otr7771ExfYTPTvfN8ZJ1pbr5Iklgt4xg==", + "license": "ISC", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "license": "MIT" - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/yallist": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" }, "packages/safe-chain": { "name": "@aikidosec/safe-chain", @@ -1688,9 +1199,9 @@ "chalk": "5.4.1", "https-proxy-agent": "7.0.6", "ini": "6.0.0", - "make-fetch-happen": "14.0.3", - "node-forge": "1.3.1", - "npm-registry-fetch": "18.0.2", + "make-fetch-happen": "15.0.3", + "node-forge": "1.3.2", + "npm-registry-fetch": "19.1.1", "semver": "7.7.2" }, "bin": { @@ -1704,6 +1215,7 @@ "aikido-pnpx": "bin/aikido-pnpx.js", "aikido-python": "bin/aikido-python.js", "aikido-python3": "bin/aikido-python3.js", + "aikido-uv": "bin/aikido-uv.js", "aikido-yarn": "bin/aikido-yarn.js", "safe-chain": "bin/safe-chain.js" }, diff --git a/packages/safe-chain/package.json b/packages/safe-chain/package.json index 15279d6..9f90b42 100644 --- a/packages/safe-chain/package.json +++ b/packages/safe-chain/package.json @@ -40,9 +40,9 @@ "chalk": "5.4.1", "https-proxy-agent": "7.0.6", "ini": "6.0.0", - "make-fetch-happen": "14.0.3", - "node-forge": "1.3.1", - "npm-registry-fetch": "18.0.2", + "make-fetch-happen": "15.0.3", + "node-forge": "1.3.2", + "npm-registry-fetch": "19.1.1", "semver": "7.7.2" }, "devDependencies": { From b14ff4cb3375cc258db5e0e9c92a863d17b41b37 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Thu, 27 Nov 2025 15:01:57 +0100 Subject: [PATCH 02/86] First time build of the safe-chain binaries --- .github/workflows/test-on-pr.yml | 12 + package-lock.json | 486 ++++++++++++++++++++++ packages/safe-chain/bin/aikido-bun.js | 6 +- packages/safe-chain/bin/aikido-bunx.js | 6 +- packages/safe-chain/bin/aikido-npm.js | 6 +- packages/safe-chain/bin/aikido-npx.js | 6 +- packages/safe-chain/bin/aikido-pip.js | 8 +- packages/safe-chain/bin/aikido-pip3.js | 8 +- packages/safe-chain/bin/aikido-pnpm.js | 6 +- packages/safe-chain/bin/aikido-pnpx.js | 6 +- packages/safe-chain/bin/aikido-python.js | 28 +- packages/safe-chain/bin/aikido-python3.js | 28 +- packages/safe-chain/bin/aikido-uv.js | 8 +- packages/safe-chain/bin/aikido-yarn.js | 6 +- packages/safe-chain/bin/safe-chain.js | 18 +- packages/safe-chain/package.json | 23 + 16 files changed, 608 insertions(+), 53 deletions(-) diff --git a/.github/workflows/test-on-pr.yml b/.github/workflows/test-on-pr.yml index f8087ef..81a3e45 100644 --- a/.github/workflows/test-on-pr.yml +++ b/.github/workflows/test-on-pr.yml @@ -43,6 +43,18 @@ jobs: name: safe-chain-package path: aikidosec-safe-chain-*.tgz + - name: Create binaries + run: | + npm i -g esbuild@0.27.0 @yao-pkg/pkg@6.10.1 + mkdir "dist" + esbuild "./packages/safe-chain/bin/safe-chain.js" --bundle --platform=node --target=node22 > "./dist/safe-chain.cjs" + pkg "./dist/safe-chain.cjs" --targets node22-macos-x64 --output "./dist/macos-x64/safe-chain" + pkg "./dist/safe-chain.cjs" --targets node22-macos-arm64 --output "./dist/macos-arm64/safe-chain" + pkg "./dist/safe-chain.cjs" --targets node22-linux-x64 --output "./dist/linux-x64/safe-chain" + pkg "./dist/safe-chain.cjs" --targets node22-linux-arm64 --output "./dist/linux-arm64/safe-chain" + pkg "./dist/safe-chain.cjs" --targets node22-win-x64 --output "./dist/win-x64/safe-chain.exe" + pkg "./dist/safe-chain.cjs" --targets node22-win-arm64 --output "./dist/win-arm64/safe-chain.exe" + e2e-tests: name: Run E2E tests diff --git a/package-lock.json b/package-lock.json index 60bd1bf..e25b316 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,448 @@ "resolved": "test/e2e", "link": true }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.0.tgz", + "integrity": "sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.0.tgz", + "integrity": "sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.0.tgz", + "integrity": "sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.0.tgz", + "integrity": "sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.0.tgz", + "integrity": "sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.0.tgz", + "integrity": "sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.0.tgz", + "integrity": "sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.0.tgz", + "integrity": "sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.0.tgz", + "integrity": "sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.0.tgz", + "integrity": "sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.0.tgz", + "integrity": "sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.0.tgz", + "integrity": "sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.0.tgz", + "integrity": "sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.0.tgz", + "integrity": "sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.0.tgz", + "integrity": "sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.0.tgz", + "integrity": "sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.0.tgz", + "integrity": "sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.0.tgz", + "integrity": "sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.0.tgz", + "integrity": "sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.0.tgz", + "integrity": "sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.0.tgz", + "integrity": "sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.0.tgz", + "integrity": "sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.0.tgz", + "integrity": "sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.0.tgz", + "integrity": "sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.0.tgz", + "integrity": "sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.0.tgz", + "integrity": "sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -636,6 +1078,48 @@ "node": ">= 0.4" } }, + "node_modules/esbuild": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.0.tgz", + "integrity": "sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.0", + "@esbuild/android-arm": "0.27.0", + "@esbuild/android-arm64": "0.27.0", + "@esbuild/android-x64": "0.27.0", + "@esbuild/darwin-arm64": "0.27.0", + "@esbuild/darwin-x64": "0.27.0", + "@esbuild/freebsd-arm64": "0.27.0", + "@esbuild/freebsd-x64": "0.27.0", + "@esbuild/linux-arm": "0.27.0", + "@esbuild/linux-arm64": "0.27.0", + "@esbuild/linux-ia32": "0.27.0", + "@esbuild/linux-loong64": "0.27.0", + "@esbuild/linux-mips64el": "0.27.0", + "@esbuild/linux-ppc64": "0.27.0", + "@esbuild/linux-riscv64": "0.27.0", + "@esbuild/linux-s390x": "0.27.0", + "@esbuild/linux-x64": "0.27.0", + "@esbuild/netbsd-arm64": "0.27.0", + "@esbuild/netbsd-x64": "0.27.0", + "@esbuild/openbsd-arm64": "0.27.0", + "@esbuild/openbsd-x64": "0.27.0", + "@esbuild/openharmony-arm64": "0.27.0", + "@esbuild/sunos-x64": "0.27.0", + "@esbuild/win32-arm64": "0.27.0", + "@esbuild/win32-ia32": "0.27.0", + "@esbuild/win32-x64": "0.27.0" + } + }, "node_modules/foreground-child": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", @@ -1704,6 +2188,7 @@ "aikido-pnpx": "bin/aikido-pnpx.js", "aikido-python": "bin/aikido-python.js", "aikido-python3": "bin/aikido-python3.js", + "aikido-uv": "bin/aikido-uv.js", "aikido-yarn": "bin/aikido-yarn.js", "safe-chain": "bin/safe-chain.js" }, @@ -1714,6 +2199,7 @@ "@types/node-forge": "^1.3.14", "@types/npm-registry-fetch": "^8.0.9", "@types/semver": "^7.7.1", + "esbuild": "^0.27.0", "typescript": "^5.9.3" } }, diff --git a/packages/safe-chain/bin/aikido-bun.js b/packages/safe-chain/bin/aikido-bun.js index c128445..9d11784 100755 --- a/packages/safe-chain/bin/aikido-bun.js +++ b/packages/safe-chain/bin/aikido-bun.js @@ -7,6 +7,8 @@ import { setEcoSystem, ECOSYSTEM_JS } from "../src/config/settings.js"; setEcoSystem(ECOSYSTEM_JS); const packageManagerName = "bun"; initializePackageManager(packageManagerName); -var exitCode = await main(process.argv.slice(2)); -process.exit(exitCode); +(async () => { + var exitCode = await main(process.argv.slice(2)); + process.exit(exitCode); +})(); diff --git a/packages/safe-chain/bin/aikido-bunx.js b/packages/safe-chain/bin/aikido-bunx.js index 2e83793..bcc93a6 100755 --- a/packages/safe-chain/bin/aikido-bunx.js +++ b/packages/safe-chain/bin/aikido-bunx.js @@ -7,6 +7,8 @@ import { setEcoSystem, ECOSYSTEM_JS } from "../src/config/settings.js"; setEcoSystem(ECOSYSTEM_JS); const packageManagerName = "bunx"; initializePackageManager(packageManagerName); -var exitCode = await main(process.argv.slice(2)); -process.exit(exitCode); +(async () => { + var exitCode = await main(process.argv.slice(2)); + process.exit(exitCode); +})(); diff --git a/packages/safe-chain/bin/aikido-npm.js b/packages/safe-chain/bin/aikido-npm.js index a50d9b5..7916f7e 100755 --- a/packages/safe-chain/bin/aikido-npm.js +++ b/packages/safe-chain/bin/aikido-npm.js @@ -7,6 +7,8 @@ import { setEcoSystem, ECOSYSTEM_JS } from "../src/config/settings.js"; setEcoSystem(ECOSYSTEM_JS); const packageManagerName = "npm"; initializePackageManager(packageManagerName); -var exitCode = await main(process.argv.slice(2)); -process.exit(exitCode); +(async () => { + var exitCode = await main(process.argv.slice(2)); + process.exit(exitCode); +})(); diff --git a/packages/safe-chain/bin/aikido-npx.js b/packages/safe-chain/bin/aikido-npx.js index e1687d3..58f3491 100755 --- a/packages/safe-chain/bin/aikido-npx.js +++ b/packages/safe-chain/bin/aikido-npx.js @@ -7,6 +7,8 @@ import { setEcoSystem, ECOSYSTEM_JS } from "../src/config/settings.js"; setEcoSystem(ECOSYSTEM_JS); const packageManagerName = "npx"; initializePackageManager(packageManagerName); -var exitCode = await main(process.argv.slice(2)); -process.exit(exitCode); +(async () => { + var exitCode = await main(process.argv.slice(2)); + process.exit(exitCode); +})(); diff --git a/packages/safe-chain/bin/aikido-pip.js b/packages/safe-chain/bin/aikido-pip.js index 39184f0..006e661 100755 --- a/packages/safe-chain/bin/aikido-pip.js +++ b/packages/safe-chain/bin/aikido-pip.js @@ -13,6 +13,8 @@ setCurrentPipInvocation(PIP_INVOCATIONS.PIP); initializePackageManager(PIP_PACKAGE_MANAGER); -// Pass through only user-supplied pip args -var exitCode = await main(process.argv.slice(2)); -process.exit(exitCode); +(async () => { + // Pass through only user-supplied pip args + var exitCode = await main(process.argv.slice(2)); + process.exit(exitCode); +})(); diff --git a/packages/safe-chain/bin/aikido-pip3.js b/packages/safe-chain/bin/aikido-pip3.js index e388383..e831afe 100755 --- a/packages/safe-chain/bin/aikido-pip3.js +++ b/packages/safe-chain/bin/aikido-pip3.js @@ -14,6 +14,8 @@ setCurrentPipInvocation(PIP_INVOCATIONS.PIP3); // Create package manager initializePackageManager(PIP_PACKAGE_MANAGER); -// Pass through only user-supplied pip args -var exitCode = await main(process.argv.slice(2)); -process.exit(exitCode); +(async () => { + // Pass through only user-supplied pip args + var exitCode = await main(process.argv.slice(2)); + process.exit(exitCode); +})(); diff --git a/packages/safe-chain/bin/aikido-pnpm.js b/packages/safe-chain/bin/aikido-pnpm.js index cf5125e..64bc755 100755 --- a/packages/safe-chain/bin/aikido-pnpm.js +++ b/packages/safe-chain/bin/aikido-pnpm.js @@ -7,6 +7,8 @@ import { setEcoSystem, ECOSYSTEM_JS } from "../src/config/settings.js"; setEcoSystem(ECOSYSTEM_JS); const packageManagerName = "pnpm"; initializePackageManager(packageManagerName); -var exitCode = await main(process.argv.slice(2)); -process.exit(exitCode); +(async () => { + var exitCode = await main(process.argv.slice(2)); + process.exit(exitCode); +})(); diff --git a/packages/safe-chain/bin/aikido-pnpx.js b/packages/safe-chain/bin/aikido-pnpx.js index 6182810..11ee45c 100755 --- a/packages/safe-chain/bin/aikido-pnpx.js +++ b/packages/safe-chain/bin/aikido-pnpx.js @@ -7,6 +7,8 @@ import { setEcoSystem, ECOSYSTEM_JS } from "../src/config/settings.js"; setEcoSystem(ECOSYSTEM_JS); const packageManagerName = "pnpx"; initializePackageManager(packageManagerName); -var exitCode = await main(process.argv.slice(2)); -process.exit(exitCode); +(async () => { + var exitCode = await main(process.argv.slice(2)); + process.exit(exitCode); +})(); diff --git a/packages/safe-chain/bin/aikido-python.js b/packages/safe-chain/bin/aikido-python.js index 1ef4e34..29c38e6 100755 --- a/packages/safe-chain/bin/aikido-python.js +++ b/packages/safe-chain/bin/aikido-python.js @@ -11,18 +11,20 @@ setEcoSystem(ECOSYSTEM_PY); // Strip nodejs and wrapper script from args let argv = process.argv.slice(2); -if (argv[0] === '-m' && (argv[1] === 'pip' || argv[1] === 'pip3')) { - setEcoSystem(ECOSYSTEM_PY); - setCurrentPipInvocation(argv[1] === 'pip3' ? PIP_INVOCATIONS.PY_PIP3 : PIP_INVOCATIONS.PY_PIP); - initializePackageManager(PIP_PACKAGE_MANAGER); +(async () => { + if (argv[0] === '-m' && (argv[1] === 'pip' || argv[1] === 'pip3')) { + setEcoSystem(ECOSYSTEM_PY); + setCurrentPipInvocation(argv[1] === 'pip3' ? PIP_INVOCATIONS.PY_PIP3 : PIP_INVOCATIONS.PY_PIP); + initializePackageManager(PIP_PACKAGE_MANAGER); - // Strip off the '-m pip' or '-m pip3' from the args - argv = argv.slice(2); + // Strip off the '-m pip' or '-m pip3' from the args + argv = argv.slice(2); - var exitCode = await main(argv); - process.exit(exitCode); -} else { - // Forward to real python binary for non-pip flows - const { spawn } = await import('child_process'); - spawn('python', argv, { stdio: 'inherit' }); -} + var exitCode = await main(argv); + process.exit(exitCode); + } else { + // Forward to real python binary for non-pip flows + const { spawn } = await import('child_process'); + spawn('python', argv, { stdio: 'inherit' }); + } +})(); diff --git a/packages/safe-chain/bin/aikido-python3.js b/packages/safe-chain/bin/aikido-python3.js index f53e5d2..997a88d 100755 --- a/packages/safe-chain/bin/aikido-python3.js +++ b/packages/safe-chain/bin/aikido-python3.js @@ -11,18 +11,20 @@ setEcoSystem(ECOSYSTEM_PY); // Strip nodejs and wrapper script from args let argv = process.argv.slice(2); -if (argv[0] === '-m' && (argv[1] === 'pip' || argv[1] === 'pip3')) { - setEcoSystem(ECOSYSTEM_PY); - setCurrentPipInvocation(argv[1] === 'pip3' ? PIP_INVOCATIONS.PY3_PIP3 : PIP_INVOCATIONS.PY3_PIP); - initializePackageManager(PIP_PACKAGE_MANAGER); +(async () => { + if (argv[0] === '-m' && (argv[1] === 'pip' || argv[1] === 'pip3')) { + setEcoSystem(ECOSYSTEM_PY); + setCurrentPipInvocation(argv[1] === 'pip3' ? PIP_INVOCATIONS.PY3_PIP3 : PIP_INVOCATIONS.PY3_PIP); + initializePackageManager(PIP_PACKAGE_MANAGER); - // Strip off the '-m pip' or '-m pip3' from the args - argv = argv.slice(2); + // Strip off the '-m pip' or '-m pip3' from the args + argv = argv.slice(2); - var exitCode = await main(argv); - process.exit(exitCode); -} else { - // Forward to real python3 binary for non-pip flows - const { spawn } = await import('child_process'); - spawn('python3', argv, { stdio: 'inherit' }); -} + var exitCode = await main(argv); + process.exit(exitCode); + } else { + // Forward to real python3 binary for non-pip flows + const { spawn } = await import('child_process'); + spawn('python3', argv, { stdio: 'inherit' }); + } +})(); diff --git a/packages/safe-chain/bin/aikido-uv.js b/packages/safe-chain/bin/aikido-uv.js index 14180f2..4e635de 100755 --- a/packages/safe-chain/bin/aikido-uv.js +++ b/packages/safe-chain/bin/aikido-uv.js @@ -9,6 +9,8 @@ setEcoSystem(ECOSYSTEM_PY); initializePackageManager("uv"); -// Pass through only user-supplied uv args -var exitCode = await main(process.argv.slice(2)); -process.exit(exitCode); +(async () => { + // Pass through only user-supplied uv args + var exitCode = await main(process.argv.slice(2)); + process.exit(exitCode); +})(); diff --git a/packages/safe-chain/bin/aikido-yarn.js b/packages/safe-chain/bin/aikido-yarn.js index eee14e8..6c428db 100755 --- a/packages/safe-chain/bin/aikido-yarn.js +++ b/packages/safe-chain/bin/aikido-yarn.js @@ -7,6 +7,8 @@ import { setEcoSystem, ECOSYSTEM_JS } from "../src/config/settings.js"; setEcoSystem(ECOSYSTEM_JS); const packageManagerName = "yarn"; initializePackageManager(packageManagerName); -var exitCode = await main(process.argv.slice(2)); -process.exit(exitCode); +(async () => { + var exitCode = await main(process.argv.slice(2)); + process.exit(exitCode); +})(); diff --git a/packages/safe-chain/bin/safe-chain.js b/packages/safe-chain/bin/safe-chain.js index 94e4e1f..738c42b 100755 --- a/packages/safe-chain/bin/safe-chain.js +++ b/packages/safe-chain/bin/safe-chain.js @@ -7,6 +7,9 @@ import { setup } from "../src/shell-integration/setup.js"; import { teardown } from "../src/shell-integration/teardown.js"; import { setupCi } from "../src/shell-integration/setup-ci.js"; import { initializeCliArguments } from "../src/config/cliArguments.js"; +import { ECOSYSTEM_JS, setEcoSystem } from "../src/config/settings.js"; +import { initializePackageManager } from "../src/packagemanager/currentPackageManager.js"; +import { main } from "../src/main.js"; if (process.argv.length < 3) { ui.writeError("No command provided. Please provide a command to execute."); @@ -19,12 +22,19 @@ initializeCliArguments(process.argv); const command = process.argv[2]; -if (command === "help" || command === "--help" || command === "-h") { +const pkgManagerCommands = ["npm", "npx", "yarn"]; + +if (pkgManagerCommands.includes(command)) { + setEcoSystem(ECOSYSTEM_JS); + initializePackageManager(command); + (async () => { + var exitCode = await main(process.argv.slice(3)); + process.exit(exitCode); + })(); +} else if (command === "help" || command === "--help" || command === "-h") { writeHelp(); process.exit(0); -} - -if (command === "setup") { +}else if (command === "setup") { setup(); } else if (command === "teardown") { teardown(); diff --git a/packages/safe-chain/package.json b/packages/safe-chain/package.json index 15279d6..abf2d69 100644 --- a/packages/safe-chain/package.json +++ b/packages/safe-chain/package.json @@ -52,6 +52,7 @@ "@types/node-forge": "^1.3.14", "@types/npm-registry-fetch": "^8.0.9", "@types/semver": "^7.7.1", + "esbuild": "^0.27.0", "typescript": "^5.9.3" }, "main": "src/main.js", @@ -63,5 +64,27 @@ "type": "git", "url": "git+https://github.com/AikidoSec/safe-chain.git", "directory": "packages/safe-chain" + }, + "pkg": { + "targets": [ + "node22-linux-x64", + "node22-linux-arm64", + "node22-macos-x64", + "node22-macos-arm64", + "node22-win-x64", + "node22-win-arm64" + ], + "outputPath": "dist", + "assets": [ + "node_modules/certifi/**/*" + ], + "scripts": [ + "src/**/*.js", + "bin/**/*.js" + ], + "ignore": [ + "**/*.spec.js", + "test/**" + ] } } From 430792626b042a6cf4fe7699d546ad12d13a2322 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Thu, 27 Nov 2025 15:07:54 +0100 Subject: [PATCH 03/86] Publish the created binaries --- .github/workflows/test-on-pr.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/test-on-pr.yml b/.github/workflows/test-on-pr.yml index 81a3e45..e281d2c 100644 --- a/.github/workflows/test-on-pr.yml +++ b/.github/workflows/test-on-pr.yml @@ -54,6 +54,13 @@ jobs: pkg "./dist/safe-chain.cjs" --targets node22-linux-arm64 --output "./dist/linux-arm64/safe-chain" pkg "./dist/safe-chain.cjs" --targets node22-win-x64 --output "./dist/win-x64/safe-chain.exe" pkg "./dist/safe-chain.cjs" --targets node22-win-arm64 --output "./dist/win-arm64/safe-chain.exe" + ls -la ./dist + + - name: Upload safe-chain-binaries + uses: actions/upload-artifact@v4 + with: + name: safe-chain-package + path: aikidosec-safe-chain-*.tgz e2e-tests: name: Run E2E tests From a632ef9bddf07fb601b65dfc845968ced669fad6 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Thu, 27 Nov 2025 15:11:11 +0100 Subject: [PATCH 04/86] Add the correct binaries --- .github/workflows/test-on-pr.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-on-pr.yml b/.github/workflows/test-on-pr.yml index e281d2c..644a928 100644 --- a/.github/workflows/test-on-pr.yml +++ b/.github/workflows/test-on-pr.yml @@ -59,8 +59,8 @@ jobs: - name: Upload safe-chain-binaries uses: actions/upload-artifact@v4 with: - name: safe-chain-package - path: aikidosec-safe-chain-*.tgz + name: safe-chain-binaries + path: dist/* e2e-tests: name: Run E2E tests From 543f10657cd3f8d4e005ba612a66629fad037ddc Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Thu, 27 Nov 2025 15:21:36 +0100 Subject: [PATCH 05/86] Separate pipeline for binary creation --- .github/workflows/create-artifact.yml | 86 +++++++++++++++++++++++++++ .github/workflows/test-on-pr.yml | 19 ------ 2 files changed, 86 insertions(+), 19 deletions(-) create mode 100644 .github/workflows/create-artifact.yml diff --git a/.github/workflows/create-artifact.yml b/.github/workflows/create-artifact.yml new file mode 100644 index 0000000..f7984f1 --- /dev/null +++ b/.github/workflows/create-artifact.yml @@ -0,0 +1,86 @@ +name: Create binaries + +on: pull_request + +jobs: + + create-binaries: + + name: Create binary for ${{ matrix.os }}-${{ matrix.arch }} + + runs-on: ${{ matrix.runner }} + + strategy: + matrix: + include: + - os: macos + arch: x64 + runner: macos-15-intel + target: node22-macos-x64 + extension: '' + - os: macos + arch: arm64 + runner: macos-latest + target: node22-macos-arm64 + extension: '' + - os: linux + arch: x64 + runner: ubuntu-latest + target: node22-linux-x64 + extension: '' + - os: linux + arch: arm64 + runner: ubuntu-24.04-arm + target: node22-linux-arm64 + extension: '' + - os: win + arch: x64 + runner: windows-latest + target: node22-win-x64 + extension: '.exe' + - os: win + arch: arm64 + runner: windows-11-arm + target: node22-win-arm64 + extension: '.exe' + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: "lts/*" + + - name: Setup safe-chain + run: | + npm i -g @aikidosec/safe-chain + safe-chain setup-ci + + - name: Install dependencies + run: npm ci + + - name: Create binary (Unix) + if: matrix.os != 'win' + run: | + npm i -g esbuild@0.27.0 @yao-pkg/pkg@6.10.1 + mkdir -p "dist/${{ matrix.os }}-${{ matrix.arch }}" + esbuild "./packages/safe-chain/bin/safe-chain.js" --bundle --platform=node --target=node22 > "./dist/safe-chain.cjs" + pkg "./dist/safe-chain.cjs" --targets ${{ matrix.target }} --output "./dist/${{ matrix.os }}-${{ matrix.arch }}/safe-chain${{ matrix.extension }}" + shell: bash + + - name: Create binary (Windows) + if: matrix.os == 'win' + run: | + npm i -g esbuild@0.27.0 @yao-pkg/pkg@6.10.1 + New-Item -ItemType Directory -Force -Path "dist/${{ matrix.os }}-${{ matrix.arch }}" + esbuild "./packages/safe-chain/bin/safe-chain.js" --bundle --platform=node --target=node22 | Out-File -FilePath "./dist/safe-chain.cjs" -Encoding utf8 + pkg "./dist/safe-chain.cjs" --targets ${{ matrix.target }} --output "./dist/${{ matrix.os }}-${{ matrix.arch }}/safe-chain${{ matrix.extension }}" + shell: powershell + + - name: Upload binary artifact + uses: actions/upload-artifact@v4 + with: + name: safe-chain-${{ matrix.os }}-${{ matrix.arch }} + path: dist/${{ matrix.os }}-${{ matrix.arch }}/* \ No newline at end of file diff --git a/.github/workflows/test-on-pr.yml b/.github/workflows/test-on-pr.yml index 644a928..f8087ef 100644 --- a/.github/workflows/test-on-pr.yml +++ b/.github/workflows/test-on-pr.yml @@ -43,25 +43,6 @@ jobs: name: safe-chain-package path: aikidosec-safe-chain-*.tgz - - name: Create binaries - run: | - npm i -g esbuild@0.27.0 @yao-pkg/pkg@6.10.1 - mkdir "dist" - esbuild "./packages/safe-chain/bin/safe-chain.js" --bundle --platform=node --target=node22 > "./dist/safe-chain.cjs" - pkg "./dist/safe-chain.cjs" --targets node22-macos-x64 --output "./dist/macos-x64/safe-chain" - pkg "./dist/safe-chain.cjs" --targets node22-macos-arm64 --output "./dist/macos-arm64/safe-chain" - pkg "./dist/safe-chain.cjs" --targets node22-linux-x64 --output "./dist/linux-x64/safe-chain" - pkg "./dist/safe-chain.cjs" --targets node22-linux-arm64 --output "./dist/linux-arm64/safe-chain" - pkg "./dist/safe-chain.cjs" --targets node22-win-x64 --output "./dist/win-x64/safe-chain.exe" - pkg "./dist/safe-chain.cjs" --targets node22-win-arm64 --output "./dist/win-arm64/safe-chain.exe" - ls -la ./dist - - - name: Upload safe-chain-binaries - uses: actions/upload-artifact@v4 - with: - name: safe-chain-binaries - path: dist/* - e2e-tests: name: Run E2E tests From dbbe0f27bf02d01392ffebfcda28e8af1511f180 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Thu, 27 Nov 2025 15:26:40 +0100 Subject: [PATCH 06/86] Speed up Windows --- .github/workflows/create-artifact.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/create-artifact.yml b/.github/workflows/create-artifact.yml index f7984f1..6be270e 100644 --- a/.github/workflows/create-artifact.yml +++ b/.github/workflows/create-artifact.yml @@ -54,6 +54,7 @@ jobs: node-version: "lts/*" - name: Setup safe-chain + if: matrix.os != 'win' run: | npm i -g @aikidosec/safe-chain safe-chain setup-ci From 98231b8d25d16ca447089a53d1a1c790f1df70e4 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Thu, 27 Nov 2025 15:30:39 +0100 Subject: [PATCH 07/86] Ignore scripts on install for binaries --- .github/workflows/create-artifact.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/create-artifact.yml b/.github/workflows/create-artifact.yml index 6be270e..44d2e3d 100644 --- a/.github/workflows/create-artifact.yml +++ b/.github/workflows/create-artifact.yml @@ -60,7 +60,7 @@ jobs: safe-chain setup-ci - name: Install dependencies - run: npm ci + run: npm ci --ignore-scripts - name: Create binary (Unix) if: matrix.os != 'win' From 9c149f3bb311da4609c3b18a4c8bb098039d6fcb Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 10:51:43 +0100 Subject: [PATCH 08/86] Create and run build.js --- .github/workflows/create-artifact.yml | 34 ++----- .gitignore | 6 +- build.js | 90 +++++++++++++++++++ package-lock.json | 1 + package.json | 3 +- packages/safe-chain/bin/safe-chain.js | 25 ++++-- .../safe-chain/src/shell-integration/setup.js | 4 +- 7 files changed, 126 insertions(+), 37 deletions(-) create mode 100644 build.js diff --git a/.github/workflows/create-artifact.yml b/.github/workflows/create-artifact.yml index 44d2e3d..7716312 100644 --- a/.github/workflows/create-artifact.yml +++ b/.github/workflows/create-artifact.yml @@ -3,9 +3,7 @@ name: Create binaries on: pull_request jobs: - create-binaries: - name: Create binary for ${{ matrix.os }}-${{ matrix.arch }} runs-on: ${{ matrix.runner }} @@ -17,32 +15,32 @@ jobs: arch: x64 runner: macos-15-intel target: node22-macos-x64 - extension: '' + extension: "" - os: macos arch: arm64 runner: macos-latest target: node22-macos-arm64 - extension: '' + extension: "" - os: linux arch: x64 runner: ubuntu-latest target: node22-linux-x64 - extension: '' + extension: "" - os: linux arch: arm64 runner: ubuntu-24.04-arm target: node22-linux-arm64 - extension: '' + extension: "" - os: win arch: x64 runner: windows-latest target: node22-win-x64 - extension: '.exe' + extension: ".exe" - os: win arch: arm64 runner: windows-11-arm target: node22-win-arm64 - extension: '.exe' + extension: ".exe" steps: - name: Checkout code @@ -51,10 +49,9 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v3 with: - node-version: "lts/*" + node-version: "22.x" - name: Setup safe-chain - if: matrix.os != 'win' run: | npm i -g @aikidosec/safe-chain safe-chain setup-ci @@ -65,23 +62,10 @@ jobs: - name: Create binary (Unix) if: matrix.os != 'win' run: | - npm i -g esbuild@0.27.0 @yao-pkg/pkg@6.10.1 - mkdir -p "dist/${{ matrix.os }}-${{ matrix.arch }}" - esbuild "./packages/safe-chain/bin/safe-chain.js" --bundle --platform=node --target=node22 > "./dist/safe-chain.cjs" - pkg "./dist/safe-chain.cjs" --targets ${{ matrix.target }} --output "./dist/${{ matrix.os }}-${{ matrix.arch }}/safe-chain${{ matrix.extension }}" - shell: bash - - - name: Create binary (Windows) - if: matrix.os == 'win' - run: | - npm i -g esbuild@0.27.0 @yao-pkg/pkg@6.10.1 - New-Item -ItemType Directory -Force -Path "dist/${{ matrix.os }}-${{ matrix.arch }}" - esbuild "./packages/safe-chain/bin/safe-chain.js" --bundle --platform=node --target=node22 | Out-File -FilePath "./dist/safe-chain.cjs" -Encoding utf8 - pkg "./dist/safe-chain.cjs" --targets ${{ matrix.target }} --output "./dist/${{ matrix.os }}-${{ matrix.arch }}/safe-chain${{ matrix.extension }}" - shell: powershell + node build.js ${{ matrix.target }} - name: Upload binary artifact uses: actions/upload-artifact@v4 with: name: safe-chain-${{ matrix.os }}-${{ matrix.arch }} - path: dist/${{ matrix.os }}-${{ matrix.arch }}/* \ No newline at end of file + path: dist/* diff --git a/.gitignore b/.gitignore index acae695..7c44b34 100644 --- a/.gitignore +++ b/.gitignore @@ -143,4 +143,8 @@ vite.config.ts.timestamp-* # AI Claude.md .claude -.reference \ No newline at end of file +.reference + +# Build files +build/ +dist/ diff --git a/build.js b/build.js new file mode 100644 index 0000000..55ad3ec --- /dev/null +++ b/build.js @@ -0,0 +1,90 @@ +import { build } from "esbuild"; +import { mkdir, cp, rm, readFile, writeFile } from "node:fs/promises"; +import { spawn } from "node:child_process"; + +const target = process.argv[2]; +if (!target) { + // eslint-disable-next-line no-console + console.error("Usage: node build.js "); + // eslint-disable-next-line no-console + console.error("Example: node build.js node22-macos-arm64"); + process.exit(1); +} + +(async function () { + await clearOutputFolder(); + await bundleSafeChain(); + await copyShellScripts(); + await copyAndModifyPackageJson(); + await buildSafeChainBinary(target); +})(); + +async function clearOutputFolder() { + await rm("./build", { recursive: true, force: true }); + await mkdir("./build"); +} + +async function bundleSafeChain() { + await build({ + entryPoints: ["./packages/safe-chain/bin/safe-chain.js"], + bundle: true, + platform: "node", + target: "node22", + outfile: "./build/bin/safe-chain.cjs", + }); +} + +async function copyShellScripts() { + await mkdir("./build/bin/startup-scripts", { recursive: true }); + await cp( + "./packages/safe-chain/src/shell-integration/startup-scripts/", + "./build/bin/startup-scripts", + { recursive: true } + ); +} +async function copyAndModifyPackageJson() { + const packageJsonContent = await readFile( + "./packages/safe-chain/package.json", + "utf-8" + ); + const packageJson = JSON.parse(packageJsonContent); + + delete packageJson.main; + delete packageJson.scripts; + delete packageJson.exports; + delete packageJson.dependencies; + delete packageJson.devDependencies; + + packageJson.bin = { + "safe-chain": "bin/safe-chain.cjs", + }; + packageJson.type = "commonjs"; + packageJson.pkg = { + outputPath: "dist", + assets: ["node_modules/certifi/**/*", "bin/startup-scripts/**/*"], + }; + + await writeFile("./build/package.json", JSON.stringify(packageJson, null, 2)); + + return packageJson; +} + +function buildSafeChainBinary(target) { + return new Promise((resolve, reject) => { + const pkg = spawn( + "npx", + ["pkg", "./build/package.json", `--target=${target}`], + { + stdio: "inherit", + } + ); + + pkg.on("close", (code) => { + if (code !== 0) { + reject(new Error(`pkg process exited with code ${code}`)); + } else { + resolve(); + } + }); + }); +} diff --git a/package-lock.json b/package-lock.json index a720a7f..16f42c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "test/e2e" ], "devDependencies": { + "esbuild": "^0.27.0", "oxlint": "^1.22.0" } }, diff --git a/package.json b/package.json index aa40862..8428fe4 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "author": "Aikido Security", "license": "AGPL-3.0-or-later", "devDependencies": { - "oxlint": "^1.22.0" + "oxlint": "^1.22.0", + "esbuild": "^0.27.0" } } diff --git a/packages/safe-chain/bin/safe-chain.js b/packages/safe-chain/bin/safe-chain.js index 738c42b..667a880 100755 --- a/packages/safe-chain/bin/safe-chain.js +++ b/packages/safe-chain/bin/safe-chain.js @@ -1,7 +1,6 @@ #!/usr/bin/env node import chalk from "chalk"; -import { createRequire } from "module"; import { ui } from "../src/environment/userInteraction.js"; import { setup } from "../src/shell-integration/setup.js"; import { teardown } from "../src/shell-integration/teardown.js"; @@ -10,6 +9,8 @@ import { initializeCliArguments } from "../src/config/cliArguments.js"; import { ECOSYSTEM_JS, setEcoSystem } from "../src/config/settings.js"; import { initializePackageManager } from "../src/packagemanager/currentPackageManager.js"; import { main } from "../src/main.js"; +import path from "path"; +import fs from "fs"; if (process.argv.length < 3) { ui.writeError("No command provided. Please provide a command to execute."); @@ -25,6 +26,7 @@ const command = process.argv[2]; const pkgManagerCommands = ["npm", "npx", "yarn"]; if (pkgManagerCommands.includes(command)) { + ui.writeInformation(process.argv.join(", ")); setEcoSystem(ECOSYSTEM_JS); initializePackageManager(command); (async () => { @@ -34,14 +36,16 @@ if (pkgManagerCommands.includes(command)) { } else if (command === "help" || command === "--help" || command === "-h") { writeHelp(); process.exit(0); -}else if (command === "setup") { +} else if (command === "setup") { setup(); } else if (command === "teardown") { teardown(); } else if (command === "setup-ci") { setupCi(); } else if (command === "--version" || command === "-v" || command === "-v") { - ui.writeInformation(`Current safe-chain version: ${getVersion()}`); + (async () => { + ui.writeInformation(`Current safe-chain version: ${await getVersion()}`); + })(); } else { ui.writeError(`Unknown command: ${command}.`); ui.emptyLine(); @@ -97,8 +101,15 @@ function writeHelp() { ui.emptyLine(); } -function getVersion() { - const require = createRequire(import.meta.url); - const packageJson = require("../package.json"); - return packageJson.version; +async function getVersion() { + const packageJsonPath = path.join(__dirname, "..", "package.json"); + + const data = await fs.promises.readFile(packageJsonPath); + const json = JSON.parse(data.toString("utf8")); + + if (json && json.version) { + return json.version; + } + + return "1.0.0"; } diff --git a/packages/safe-chain/src/shell-integration/setup.js b/packages/safe-chain/src/shell-integration/setup.js index e734858..cd54bb8 100644 --- a/packages/safe-chain/src/shell-integration/setup.js +++ b/packages/safe-chain/src/shell-integration/setup.js @@ -103,9 +103,7 @@ function copyStartupFiles() { } // Use absolute path for source - const __filename = fileURLToPath(import.meta.url); - const __dirname = path.dirname(__filename); - const sourcePath = path.resolve( + const sourcePath = path.join( __dirname, includePython() ? "startup-scripts/include-python" : "startup-scripts", file From a01314111861e5f32dddff094ddbfc8e0137a3a1 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 10:55:29 +0100 Subject: [PATCH 09/86] Try to fix the build --- .github/workflows/create-artifact.yml | 2 +- build.js | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/.github/workflows/create-artifact.yml b/.github/workflows/create-artifact.yml index 7716312..8a26cb1 100644 --- a/.github/workflows/create-artifact.yml +++ b/.github/workflows/create-artifact.yml @@ -53,7 +53,7 @@ jobs: - name: Setup safe-chain run: | - npm i -g @aikidosec/safe-chain + npm i -g @aikidosec/safe-chain pkg safe-chain setup-ci - name: Install dependencies diff --git a/build.js b/build.js index 55ad3ec..4ef0481 100644 --- a/build.js +++ b/build.js @@ -71,13 +71,9 @@ async function copyAndModifyPackageJson() { function buildSafeChainBinary(target) { return new Promise((resolve, reject) => { - const pkg = spawn( - "npx", - ["pkg", "./build/package.json", `--target=${target}`], - { - stdio: "inherit", - } - ); + const pkg = spawn("pkg", ["./build/package.json", `--target=${target}`], { + stdio: "inherit", + }); pkg.on("close", (code) => { if (code !== 0) { From ae514d60d8b7bbf907d22baa85084eb095825f68 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 10:56:34 +0100 Subject: [PATCH 10/86] Use shell for pkg --- build.js | 1 + 1 file changed, 1 insertion(+) diff --git a/build.js b/build.js index 4ef0481..e5e9f7d 100644 --- a/build.js +++ b/build.js @@ -73,6 +73,7 @@ function buildSafeChainBinary(target) { return new Promise((resolve, reject) => { const pkg = spawn("pkg", ["./build/package.json", `--target=${target}`], { stdio: "inherit", + shell: true, }); pkg.on("close", (code) => { From 8733f53b6b112e91ecae05c40f7c7e177e30e49e Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 10:58:10 +0100 Subject: [PATCH 11/86] Debug build --- build.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.js b/build.js index e5e9f7d..3e813ef 100644 --- a/build.js +++ b/build.js @@ -70,6 +70,8 @@ async function copyAndModifyPackageJson() { } function buildSafeChainBinary(target) { + // eslint-disable-next-line no-console + console.error("Target: " + target); return new Promise((resolve, reject) => { const pkg = spawn("pkg", ["./build/package.json", `--target=${target}`], { stdio: "inherit", From ccc8d685b2063d17317989f2f701c9556b8c70b5 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 10:59:52 +0100 Subject: [PATCH 12/86] Don't fail-fast in the pipeline matrix --- .github/workflows/create-artifact.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/create-artifact.yml b/.github/workflows/create-artifact.yml index 8a26cb1..125e89b 100644 --- a/.github/workflows/create-artifact.yml +++ b/.github/workflows/create-artifact.yml @@ -9,6 +9,7 @@ jobs: runs-on: ${{ matrix.runner }} strategy: + fail-fast: false matrix: include: - os: macos From bc51c839d0f7c54f81d116b02fbaf61886deef21 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 11:02:48 +0100 Subject: [PATCH 13/86] Try fix build again --- .github/workflows/create-artifact.yml | 5 ++--- packages/safe-chain/src/shell-integration/setup.js | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/create-artifact.yml b/.github/workflows/create-artifact.yml index 125e89b..dd279ae 100644 --- a/.github/workflows/create-artifact.yml +++ b/.github/workflows/create-artifact.yml @@ -50,7 +50,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v3 with: - node-version: "22.x" + node-version: "lts/*" - name: Setup safe-chain run: | @@ -60,8 +60,7 @@ jobs: - name: Install dependencies run: npm ci --ignore-scripts - - name: Create binary (Unix) - if: matrix.os != 'win' + - name: Create binary run: | node build.js ${{ matrix.target }} diff --git a/packages/safe-chain/src/shell-integration/setup.js b/packages/safe-chain/src/shell-integration/setup.js index cd54bb8..f8072db 100644 --- a/packages/safe-chain/src/shell-integration/setup.js +++ b/packages/safe-chain/src/shell-integration/setup.js @@ -5,7 +5,6 @@ import { knownAikidoTools, getPackageManagerList } from "./helpers.js"; import fs from "fs"; import os from "os"; import path from "path"; -import { fileURLToPath } from "url"; import { includePython } from "../config/cliArguments.js"; /** From c70659b7a1bfa580f1851cc8f1f99264d705c55b Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 11:06:43 +0100 Subject: [PATCH 14/86] Use correct pkg arg --- .github/workflows/create-artifact.yml | 2 +- build.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/create-artifact.yml b/.github/workflows/create-artifact.yml index dd279ae..938994a 100644 --- a/.github/workflows/create-artifact.yml +++ b/.github/workflows/create-artifact.yml @@ -50,7 +50,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v3 with: - node-version: "lts/*" + node-version: "22.x" - name: Setup safe-chain run: | diff --git a/build.js b/build.js index 3e813ef..3d3a9e6 100644 --- a/build.js +++ b/build.js @@ -73,7 +73,7 @@ function buildSafeChainBinary(target) { // eslint-disable-next-line no-console console.error("Target: " + target); return new Promise((resolve, reject) => { - const pkg = spawn("pkg", ["./build/package.json", `--target=${target}`], { + const pkg = spawn("pkg", ["./build/package.json", "--targets", target], { stdio: "inherit", shell: true, }); From 05f1289268b86869ea5c8d7e3746f22122c005e2 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 11:14:14 +0100 Subject: [PATCH 15/86] Run pkg from ci step --- .github/workflows/create-artifact.yml | 1 + build.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/create-artifact.yml b/.github/workflows/create-artifact.yml index 938994a..1ce0a53 100644 --- a/.github/workflows/create-artifact.yml +++ b/.github/workflows/create-artifact.yml @@ -63,6 +63,7 @@ jobs: - name: Create binary run: | node build.js ${{ matrix.target }} + pkg ./build/package.json -t ${{ matrix.target }} - name: Upload binary artifact uses: actions/upload-artifact@v4 diff --git a/build.js b/build.js index 3d3a9e6..7868390 100644 --- a/build.js +++ b/build.js @@ -16,7 +16,7 @@ if (!target) { await bundleSafeChain(); await copyShellScripts(); await copyAndModifyPackageJson(); - await buildSafeChainBinary(target); + // await buildSafeChainBinary(target); })(); async function clearOutputFolder() { @@ -73,7 +73,7 @@ function buildSafeChainBinary(target) { // eslint-disable-next-line no-console console.error("Target: " + target); return new Promise((resolve, reject) => { - const pkg = spawn("pkg", ["./build/package.json", "--targets", target], { + const pkg = spawn("pkg", ["./build/package.json", "-t", target], { stdio: "inherit", shell: true, }); From 7f1710fb7302efe6a0f0dd6976ce43fe2dd0d9e7 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 11:17:28 +0100 Subject: [PATCH 16/86] Move target to package.json --- .github/workflows/create-artifact.yml | 2 +- build.js | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/create-artifact.yml b/.github/workflows/create-artifact.yml index 1ce0a53..8684ac7 100644 --- a/.github/workflows/create-artifact.yml +++ b/.github/workflows/create-artifact.yml @@ -63,7 +63,7 @@ jobs: - name: Create binary run: | node build.js ${{ matrix.target }} - pkg ./build/package.json -t ${{ matrix.target }} + pkg ./build/package.json - name: Upload binary artifact uses: actions/upload-artifact@v4 diff --git a/build.js b/build.js index 7868390..b15b936 100644 --- a/build.js +++ b/build.js @@ -15,7 +15,7 @@ if (!target) { await clearOutputFolder(); await bundleSafeChain(); await copyShellScripts(); - await copyAndModifyPackageJson(); + await copyAndModifyPackageJson(target); // await buildSafeChainBinary(target); })(); @@ -42,7 +42,7 @@ async function copyShellScripts() { { recursive: true } ); } -async function copyAndModifyPackageJson() { +async function copyAndModifyPackageJson(target) { const packageJsonContent = await readFile( "./packages/safe-chain/package.json", "utf-8" @@ -62,6 +62,7 @@ async function copyAndModifyPackageJson() { packageJson.pkg = { outputPath: "dist", assets: ["node_modules/certifi/**/*", "bin/startup-scripts/**/*"], + targets: [target], }; await writeFile("./build/package.json", JSON.stringify(packageJson, null, 2)); From 97883a42c292e5fa24dc138acc6e5ff195d31acb Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 11:24:08 +0100 Subject: [PATCH 17/86] Use node 24 --- .github/workflows/create-artifact.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/create-artifact.yml b/.github/workflows/create-artifact.yml index 8684ac7..8e718f9 100644 --- a/.github/workflows/create-artifact.yml +++ b/.github/workflows/create-artifact.yml @@ -15,32 +15,32 @@ jobs: - os: macos arch: x64 runner: macos-15-intel - target: node22-macos-x64 + target: node24-macos-x64 extension: "" - os: macos arch: arm64 runner: macos-latest - target: node22-macos-arm64 + target: node24-macos-arm64 extension: "" - os: linux arch: x64 runner: ubuntu-latest - target: node22-linux-x64 + target: node24-linux-x64 extension: "" - os: linux arch: arm64 runner: ubuntu-24.04-arm - target: node22-linux-arm64 + target: node24-linux-arm64 extension: "" - os: win arch: x64 runner: windows-latest - target: node22-win-x64 + target: node24-win-x64 extension: ".exe" - os: win arch: arm64 runner: windows-11-arm - target: node22-win-arm64 + target: node24-win-arm64 extension: ".exe" steps: @@ -50,7 +50,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v3 with: - node-version: "22.x" + node-version: "24.x" - name: Setup safe-chain run: | @@ -63,7 +63,7 @@ jobs: - name: Create binary run: | node build.js ${{ matrix.target }} - pkg ./build/package.json + pkg ./build/package.json --output "./dist/safe-chain${{ matrix.extension }}" - name: Upload binary artifact uses: actions/upload-artifact@v4 From 832708299fc0492b4de468973aa087804d7fbfe0 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 11:29:40 +0100 Subject: [PATCH 18/86] Use @yao-pkg/pkg --- .github/workflows/create-artifact.yml | 2 +- build.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/create-artifact.yml b/.github/workflows/create-artifact.yml index 8e718f9..63badb5 100644 --- a/.github/workflows/create-artifact.yml +++ b/.github/workflows/create-artifact.yml @@ -54,7 +54,7 @@ jobs: - name: Setup safe-chain run: | - npm i -g @aikidosec/safe-chain pkg + npm i -g @aikidosec/safe-chain @yao-pkg/pkg safe-chain setup-ci - name: Install dependencies diff --git a/build.js b/build.js index b15b936..7c5ac27 100644 --- a/build.js +++ b/build.js @@ -29,7 +29,7 @@ async function bundleSafeChain() { entryPoints: ["./packages/safe-chain/bin/safe-chain.js"], bundle: true, platform: "node", - target: "node22", + target: "node24", outfile: "./build/bin/safe-chain.cjs", }); } From 8c2e8c959760a391a52557bf8487aa16bc11538f Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 11:31:47 +0100 Subject: [PATCH 19/86] Build safe-chain binaries in build.js --- .github/workflows/create-artifact.yml | 3 +-- build.js | 14 +++++++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/create-artifact.yml b/.github/workflows/create-artifact.yml index 63badb5..6d479c7 100644 --- a/.github/workflows/create-artifact.yml +++ b/.github/workflows/create-artifact.yml @@ -54,7 +54,7 @@ jobs: - name: Setup safe-chain run: | - npm i -g @aikidosec/safe-chain @yao-pkg/pkg + npm i -g @aikidosec/safe-chain safe-chain setup-ci - name: Install dependencies @@ -63,7 +63,6 @@ jobs: - name: Create binary run: | node build.js ${{ matrix.target }} - pkg ./build/package.json --output "./dist/safe-chain${{ matrix.extension }}" - name: Upload binary artifact uses: actions/upload-artifact@v4 diff --git a/build.js b/build.js index 7c5ac27..5dc7254 100644 --- a/build.js +++ b/build.js @@ -16,7 +16,7 @@ if (!target) { await bundleSafeChain(); await copyShellScripts(); await copyAndModifyPackageJson(target); - // await buildSafeChainBinary(target); + await buildSafeChainBinary(target); })(); async function clearOutputFolder() { @@ -74,10 +74,14 @@ function buildSafeChainBinary(target) { // eslint-disable-next-line no-console console.error("Target: " + target); return new Promise((resolve, reject) => { - const pkg = spawn("pkg", ["./build/package.json", "-t", target], { - stdio: "inherit", - shell: true, - }); + const pkg = spawn( + "npx", + ["@yao-pkg/pkg", "./build/package.json", "-t", target], + { + stdio: "inherit", + shell: true, + } + ); pkg.on("close", (code) => { if (code !== 0) { From f1ee6567df05a96715f94543be11a751d1802270 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 12:57:48 +0100 Subject: [PATCH 20/86] Fix __dirname for esm / fix e2e tests. --- build.js | 19 ++++++++++----- packages/safe-chain/bin/safe-chain.js | 23 +++++++++++++++++-- .../src/shell-integration/setup-ci.js | 18 ++++++++++----- .../safe-chain/src/shell-integration/setup.js | 13 ++++++++++- .../startup-scripts/init-posix.sh | 23 ++++++++----------- 5 files changed, 67 insertions(+), 29 deletions(-) diff --git a/build.js b/build.js index 5dc7254..3860646 100644 --- a/build.js +++ b/build.js @@ -15,7 +15,7 @@ if (!target) { await clearOutputFolder(); await bundleSafeChain(); await copyShellScripts(); - await copyAndModifyPackageJson(target); + await copyAndModifyPackageJson(); await buildSafeChainBinary(target); })(); @@ -41,8 +41,14 @@ async function copyShellScripts() { "./build/bin/startup-scripts", { recursive: true } ); + await mkdir("./build/bin/path-wrappers", { recursive: true }); + await cp( + "./packages/safe-chain/src/shell-integration/path-wrappers/", + "./build/bin/path-wrappers", + { recursive: true } + ); } -async function copyAndModifyPackageJson(target) { +async function copyAndModifyPackageJson() { const packageJsonContent = await readFile( "./packages/safe-chain/package.json", "utf-8" @@ -61,8 +67,11 @@ async function copyAndModifyPackageJson(target) { packageJson.type = "commonjs"; packageJson.pkg = { outputPath: "dist", - assets: ["node_modules/certifi/**/*", "bin/startup-scripts/**/*"], - targets: [target], + assets: [ + "node_modules/certifi/**/*", + "bin/startup-scripts/**/*", + "bin/path-wrappers/**/*", + ], }; await writeFile("./build/package.json", JSON.stringify(packageJson, null, 2)); @@ -71,8 +80,6 @@ async function copyAndModifyPackageJson(target) { } function buildSafeChainBinary(target) { - // eslint-disable-next-line no-console - console.error("Target: " + target); return new Promise((resolve, reject) => { const pkg = spawn( "npx", diff --git a/packages/safe-chain/bin/safe-chain.js b/packages/safe-chain/bin/safe-chain.js index 667a880..48f38c5 100755 --- a/packages/safe-chain/bin/safe-chain.js +++ b/packages/safe-chain/bin/safe-chain.js @@ -10,8 +10,19 @@ import { ECOSYSTEM_JS, setEcoSystem } from "../src/config/settings.js"; import { initializePackageManager } from "../src/packagemanager/currentPackageManager.js"; import { main } from "../src/main.js"; import path from "path"; +import { fileURLToPath } from "url"; import fs from "fs"; +/** @type {string} */ +let dirname; + +if (import.meta.url) { + const filename = fileURLToPath(import.meta.url); + dirname = path.dirname(filename); +} else { + dirname = __dirname; +} + if (process.argv.length < 3) { ui.writeError("No command provided. Please provide a command to execute."); ui.emptyLine(); @@ -23,7 +34,15 @@ initializeCliArguments(process.argv); const command = process.argv[2]; -const pkgManagerCommands = ["npm", "npx", "yarn"]; +const pkgManagerCommands = [ + "npm", + "npx", + "yarn", + "bun", + "bunx", + "pnpm", + "pnpx", +]; if (pkgManagerCommands.includes(command)) { ui.writeInformation(process.argv.join(", ")); @@ -102,7 +121,7 @@ function writeHelp() { } async function getVersion() { - const packageJsonPath = path.join(__dirname, "..", "package.json"); + const packageJsonPath = path.join(dirname, "..", "package.json"); const data = await fs.promises.readFile(packageJsonPath); const json = JSON.parse(data.toString("utf8")); diff --git a/packages/safe-chain/src/shell-integration/setup-ci.js b/packages/safe-chain/src/shell-integration/setup-ci.js index f63ad32..9e0342d 100644 --- a/packages/safe-chain/src/shell-integration/setup-ci.js +++ b/packages/safe-chain/src/shell-integration/setup-ci.js @@ -8,6 +8,16 @@ import { fileURLToPath } from "url"; import { includePython } from "../config/cliArguments.js"; import { ECOSYSTEM_PY } from "../config/settings.js"; +/** @type {string} */ +let dirname; + +if (import.meta.url) { + const filename = fileURLToPath(import.meta.url); + dirname = path.dirname(filename); +} else { + dirname = __dirname; +} + /** * Loops over the detected shells and calls the setup function for each. */ @@ -37,10 +47,8 @@ export async function setupCi() { */ function createUnixShims(shimsDir) { // Read the template file - const __filename = fileURLToPath(import.meta.url); - const __dirname = path.dirname(__filename); const templatePath = path.resolve( - __dirname, + dirname, "path-wrappers", "templates", "unix-wrapper.template.sh" @@ -78,10 +86,8 @@ function createUnixShims(shimsDir) { */ function createWindowsShims(shimsDir) { // Read the template file - const __filename = fileURLToPath(import.meta.url); - const __dirname = path.dirname(__filename); const templatePath = path.resolve( - __dirname, + dirname, "path-wrappers", "templates", "windows-wrapper.template.cmd" diff --git a/packages/safe-chain/src/shell-integration/setup.js b/packages/safe-chain/src/shell-integration/setup.js index f8072db..45a1fb8 100644 --- a/packages/safe-chain/src/shell-integration/setup.js +++ b/packages/safe-chain/src/shell-integration/setup.js @@ -6,6 +6,17 @@ import fs from "fs"; import os from "os"; import path from "path"; import { includePython } from "../config/cliArguments.js"; +import { fileURLToPath } from "url"; + +/** @type {string} */ +let dirname; + +if (import.meta.url) { + const filename = fileURLToPath(import.meta.url); + dirname = path.dirname(filename); +} else { + dirname = __dirname; +} /** * Loops over the detected shells and calls the setup function for each. @@ -103,7 +114,7 @@ function copyStartupFiles() { // Use absolute path for source const sourcePath = path.join( - __dirname, + dirname, includePython() ? "startup-scripts/include-python" : "startup-scripts", file ); diff --git a/packages/safe-chain/src/shell-integration/startup-scripts/init-posix.sh b/packages/safe-chain/src/shell-integration/startup-scripts/init-posix.sh index 353c6c0..a83e749 100644 --- a/packages/safe-chain/src/shell-integration/startup-scripts/init-posix.sh +++ b/packages/safe-chain/src/shell-integration/startup-scripts/init-posix.sh @@ -9,15 +9,10 @@ function printSafeChainWarning() { function wrapSafeChainCommand() { local original_cmd="$1" - local aikido_cmd="$2" - # Remove the first 2 arguments (original_cmd and aikido_cmd) from $@ - # so that "$@" now contains only the arguments passed to the original command - shift 2 - - if command -v "$aikido_cmd" > /dev/null 2>&1; then + if command -v safe-chain > /dev/null 2>&1; then # If the aikido command is available, just run it with the provided arguments - "$aikido_cmd" "$@" + safe-chain "$@" else # If the aikido command is not available, print a warning and run the original command printSafeChainWarning "$original_cmd" @@ -27,27 +22,27 @@ function wrapSafeChainCommand() { } function npx() { - wrapSafeChainCommand "npx" "aikido-npx" "$@" + wrapSafeChainCommand "npx" "$@" } function yarn() { - wrapSafeChainCommand "yarn" "aikido-yarn" "$@" + wrapSafeChainCommand "yarn" "$@" } function pnpm() { - wrapSafeChainCommand "pnpm" "aikido-pnpm" "$@" + wrapSafeChainCommand "pnpm" "$@" } function pnpx() { - wrapSafeChainCommand "pnpx" "aikido-pnpx" "$@" + wrapSafeChainCommand "pnpx" "$@" } function bun() { - wrapSafeChainCommand "bun" "aikido-bun" "$@" + wrapSafeChainCommand "bun" "$@" } function bunx() { - wrapSafeChainCommand "bunx" "aikido-bunx" "$@" + wrapSafeChainCommand "bunx" "$@" } function npm() { @@ -58,5 +53,5 @@ function npm() { return fi - wrapSafeChainCommand "npm" "aikido-npm" "$@" + wrapSafeChainCommand "npm" "$@" } From a3bff105ccaf9c1e759c9006e0616f93482e8b59 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 14:01:11 +0100 Subject: [PATCH 21/86] Update startup scripts to use safe-chain instead of aikido-* --- packages/safe-chain/bin/safe-chain.js | 1 - .../include-python/init-pwsh.ps1 | 31 +++++++++---------- .../startup-scripts/init-fish.fish | 27 ++++++++-------- 3 files changed, 28 insertions(+), 31 deletions(-) diff --git a/packages/safe-chain/bin/safe-chain.js b/packages/safe-chain/bin/safe-chain.js index 48f38c5..3f32bff 100755 --- a/packages/safe-chain/bin/safe-chain.js +++ b/packages/safe-chain/bin/safe-chain.js @@ -45,7 +45,6 @@ const pkgManagerCommands = [ ]; if (pkgManagerCommands.includes(command)) { - ui.writeInformation(process.argv.join(", ")); setEcoSystem(ECOSYSTEM_JS); initializePackageManager(command); (async () => { diff --git a/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-pwsh.ps1 b/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-pwsh.ps1 index e2ea1c9..deb127d 100644 --- a/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-pwsh.ps1 +++ b/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-pwsh.ps1 @@ -39,12 +39,11 @@ function Invoke-RealCommand { function Invoke-WrappedCommand { param( [string]$OriginalCmd, - [string]$AikidoCmd, [string[]]$Arguments ) - if (Test-CommandAvailable $AikidoCmd) { - & $AikidoCmd @Arguments + if (Test-CommandAvailable "safe-chain") { + & safe-chain $OriginalCmd @Arguments } else { Write-SafeChainWarning $OriginalCmd @@ -53,27 +52,27 @@ function Invoke-WrappedCommand { } function npx { - Invoke-WrappedCommand "npx" "aikido-npx" $args + Invoke-WrappedCommand "npx" $args } function yarn { - Invoke-WrappedCommand "yarn" "aikido-yarn" $args + Invoke-WrappedCommand "yarn" $args } function pnpm { - Invoke-WrappedCommand "pnpm" "aikido-pnpm" $args + Invoke-WrappedCommand "pnpm" $args } function pnpx { - Invoke-WrappedCommand "pnpx" "aikido-pnpx" $args + Invoke-WrappedCommand "pnpx" $args } function bun { - Invoke-WrappedCommand "bun" "aikido-bun" $args + Invoke-WrappedCommand "bun" $args } function bunx { - Invoke-WrappedCommand "bunx" "aikido-bunx" $args + Invoke-WrappedCommand "bunx" $args } function npm { @@ -83,29 +82,29 @@ function npm { Invoke-RealCommand "npm" $args return } - - Invoke-WrappedCommand "npm" "aikido-npm" $args + + Invoke-WrappedCommand "npm" $args } function pip { - Invoke-WrappedCommand "pip" "aikido-pip" $args + Invoke-WrappedCommand "pip" $args } function pip3 { - Invoke-WrappedCommand "pip3" "aikido-pip3" $args + Invoke-WrappedCommand "pip3" $args } function uv { - Invoke-WrappedCommand "uv" "aikido-uv" $args + Invoke-WrappedCommand "uv" $args } # `python -m pip`, `python -m pip3`. function python { - Invoke-WrappedCommand 'python' 'aikido-python' $args + Invoke-WrappedCommand 'python' $args } # `python3 -m pip`, `python3 -m pip3'. function python3 { - Invoke-WrappedCommand 'python3' 'aikido-python3' $args + Invoke-WrappedCommand 'python3' $args } diff --git a/packages/safe-chain/src/shell-integration/startup-scripts/init-fish.fish b/packages/safe-chain/src/shell-integration/startup-scripts/init-fish.fish index 29d6bf3..a72380f 100644 --- a/packages/safe-chain/src/shell-integration/startup-scripts/init-fish.fish +++ b/packages/safe-chain/src/shell-integration/startup-scripts/init-fish.fish @@ -17,41 +17,40 @@ end function wrapSafeChainCommand set original_cmd $argv[1] - set aikido_cmd $argv[2] - set cmd_args $argv[3..-1] - - if type -q $aikido_cmd - # If the aikido command is available, just run it with the provided arguments - $aikido_cmd $cmd_args + set cmd_args $argv[2..-1] + + if type -q safe-chain + # If the safe-chain command is available, just run it with the provided arguments + safe-chain $original_cmd $cmd_args else - # If the aikido command is not available, print a warning and run the original command + # If the safe-chain command is not available, print a warning and run the original command printSafeChainWarning $original_cmd command $original_cmd $cmd_args end end function npx - wrapSafeChainCommand "npx" "aikido-npx" $argv + wrapSafeChainCommand "npx" $argv end function yarn - wrapSafeChainCommand "yarn" "aikido-yarn" $argv + wrapSafeChainCommand "yarn" $argv end function pnpm - wrapSafeChainCommand "pnpm" "aikido-pnpm" $argv + wrapSafeChainCommand "pnpm" $argv end function pnpx - wrapSafeChainCommand "pnpx" "aikido-pnpx" $argv + wrapSafeChainCommand "pnpx" $argv end function bun - wrapSafeChainCommand "bun" "aikido-bun" $argv + wrapSafeChainCommand "bun" $argv end function bunx - wrapSafeChainCommand "bunx" "aikido-bunx" $argv + wrapSafeChainCommand "bunx" $argv end function npm @@ -66,5 +65,5 @@ function npm end end - wrapSafeChainCommand "npm" "aikido-npm" $argv + wrapSafeChainCommand "npm" $argv end From 161f256066c0b4bb86f156d677957600c91986e6 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 14:10:01 +0100 Subject: [PATCH 22/86] Change pwsh startup script --- .../startup-scripts/init-pwsh.ps1 | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/packages/safe-chain/src/shell-integration/startup-scripts/init-pwsh.ps1 b/packages/safe-chain/src/shell-integration/startup-scripts/init-pwsh.ps1 index a449405..2106cac 100644 --- a/packages/safe-chain/src/shell-integration/startup-scripts/init-pwsh.ps1 +++ b/packages/safe-chain/src/shell-integration/startup-scripts/init-pwsh.ps1 @@ -39,12 +39,11 @@ function Invoke-RealCommand { function Invoke-WrappedCommand { param( [string]$OriginalCmd, - [string]$AikidoCmd, [string[]]$Arguments ) - if (Test-CommandAvailable $AikidoCmd) { - & $AikidoCmd @Arguments + if (Test-CommandAvailable "safe-chain") { + & safe-chain $OriginalCmd @Arguments } else { Write-SafeChainWarning $OriginalCmd @@ -53,27 +52,27 @@ function Invoke-WrappedCommand { } function npx { - Invoke-WrappedCommand "npx" "aikido-npx" $args + Invoke-WrappedCommand "npx" $args } function yarn { - Invoke-WrappedCommand "yarn" "aikido-yarn" $args + Invoke-WrappedCommand "yarn" $args } function pnpm { - Invoke-WrappedCommand "pnpm" "aikido-pnpm" $args + Invoke-WrappedCommand "pnpm" $args } function pnpx { - Invoke-WrappedCommand "pnpx" "aikido-pnpx" $args + Invoke-WrappedCommand "pnpx" $args } function bun { - Invoke-WrappedCommand "bun" "aikido-bun" $args + Invoke-WrappedCommand "bun" $args } function bunx { - Invoke-WrappedCommand "bunx" "aikido-bunx" $args + Invoke-WrappedCommand "bunx" $args } function npm { @@ -83,6 +82,6 @@ function npm { Invoke-RealCommand "npm" $args return } - - Invoke-WrappedCommand "npm" "aikido-npm" $args -} + + Invoke-WrappedCommand "npm" $args +} \ No newline at end of file From c59b8263ca23418cb10d31d99da811ddb55bc707 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 14:44:47 +0100 Subject: [PATCH 23/86] Add certify --- build.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/build.js b/build.js index 3860646..00f7464 100644 --- a/build.js +++ b/build.js @@ -15,6 +15,7 @@ if (!target) { await clearOutputFolder(); await bundleSafeChain(); await copyShellScripts(); + await copyCertifi(); await copyAndModifyPackageJson(); await buildSafeChainBinary(target); })(); @@ -31,6 +32,7 @@ async function bundleSafeChain() { platform: "node", target: "node24", outfile: "./build/bin/safe-chain.cjs", + external: ["certifi"], }); } @@ -48,6 +50,15 @@ async function copyShellScripts() { { recursive: true } ); } + +async function copyCertifi() { + await mkdir("./build/node_modules/certifi", { recursive: true }); + await cp( + "./node_modules/certifi/", + "./build/node_modules/certifi", + { recursive: true } + ); +} async function copyAndModifyPackageJson() { const packageJsonContent = await readFile( "./packages/safe-chain/package.json", From 0fffcf2cc14c7e644b3fd29eeca11d592f375326 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 14:51:54 +0100 Subject: [PATCH 24/86] Add certificate command --- packages/safe-chain/bin/safe-chain.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/safe-chain/bin/safe-chain.js b/packages/safe-chain/bin/safe-chain.js index 3f32bff..90d95cf 100755 --- a/packages/safe-chain/bin/safe-chain.js +++ b/packages/safe-chain/bin/safe-chain.js @@ -12,6 +12,7 @@ import { main } from "../src/main.js"; import path from "path"; import { fileURLToPath } from "url"; import fs from "fs"; +import { getCombinedCaBundlePath } from "../src/registryProxy/certBundle.js"; /** @type {string} */ let dirname; @@ -56,6 +57,12 @@ if (pkgManagerCommands.includes(command)) { process.exit(0); } else if (command === "setup") { setup(); +} else if (command === "certificate") { + (async function () { + const path = getCombinedCaBundlePath(); + const data = await fs.promises.readFile(path); + ui.writeInformation(data.toString("utf8")); + })(); } else if (command === "teardown") { teardown(); } else if (command === "setup-ci") { From bb3e50008a9ff95a7db0238ae5e156d3dda55702 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 14:59:28 +0100 Subject: [PATCH 25/86] Forge: usePureJavaScript --- packages/safe-chain/src/registryProxy/certUtils.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/safe-chain/src/registryProxy/certUtils.js b/packages/safe-chain/src/registryProxy/certUtils.js index 6b326c8..7a5a5c7 100644 --- a/packages/safe-chain/src/registryProxy/certUtils.js +++ b/packages/safe-chain/src/registryProxy/certUtils.js @@ -3,6 +3,11 @@ import path from "path"; import fs from "fs"; import os from "os"; +// Force node-forge to use pure JavaScript instead of native crypto +// This prevents segmentation faults in pkg binaries on Linux +// @ts-ignore - options exists but isn't in the type definitions +forge.options.usePureJavaScript = true; + const certFolder = path.join(os.homedir(), ".safe-chain", "certs"); const ca = loadCa(); From 1d00084202e2b2c86b3c11042510e35f8babab7a Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 15:03:36 +0100 Subject: [PATCH 26/86] Externalize node-forge --- build.js | 15 +++++++++------ .../safe-chain/src/registryProxy/certUtils.js | 5 ----- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/build.js b/build.js index 00f7464..eefb2d3 100644 --- a/build.js +++ b/build.js @@ -32,7 +32,7 @@ async function bundleSafeChain() { platform: "node", target: "node24", outfile: "./build/bin/safe-chain.cjs", - external: ["certifi"], + external: ["certifi", "node-forge"], }); } @@ -53,11 +53,13 @@ async function copyShellScripts() { async function copyCertifi() { await mkdir("./build/node_modules/certifi", { recursive: true }); - await cp( - "./node_modules/certifi/", - "./build/node_modules/certifi", - { recursive: true } - ); + await mkdir("./build/node_modules/certifi", { recursive: true }); + await cp("./node_modules/certifi/", "./build/node_modules/certifi", { + recursive: true, + }); + await cp("./node_modules/node-forge/", "./build/node_modules/node-forge", { + recursive: true, + }); } async function copyAndModifyPackageJson() { const packageJsonContent = await readFile( @@ -80,6 +82,7 @@ async function copyAndModifyPackageJson() { outputPath: "dist", assets: [ "node_modules/certifi/**/*", + "node_modules/node-forge/**/*", "bin/startup-scripts/**/*", "bin/path-wrappers/**/*", ], diff --git a/packages/safe-chain/src/registryProxy/certUtils.js b/packages/safe-chain/src/registryProxy/certUtils.js index 7a5a5c7..6b326c8 100644 --- a/packages/safe-chain/src/registryProxy/certUtils.js +++ b/packages/safe-chain/src/registryProxy/certUtils.js @@ -3,11 +3,6 @@ import path from "path"; import fs from "fs"; import os from "os"; -// Force node-forge to use pure JavaScript instead of native crypto -// This prevents segmentation faults in pkg binaries on Linux -// @ts-ignore - options exists but isn't in the type definitions -forge.options.usePureJavaScript = true; - const certFolder = path.join(os.homedir(), ".safe-chain", "certs"); const ca = loadCa(); From ec9a266164be80afb90dcceb449aeb47897f581e Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 15:17:29 +0100 Subject: [PATCH 27/86] Include node-forge in binary again --- build.js | 7 +------ packages/safe-chain/src/registryProxy/certUtils.js | 3 +++ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/build.js b/build.js index eefb2d3..e576c5a 100644 --- a/build.js +++ b/build.js @@ -32,7 +32,7 @@ async function bundleSafeChain() { platform: "node", target: "node24", outfile: "./build/bin/safe-chain.cjs", - external: ["certifi", "node-forge"], + external: ["certifi"], }); } @@ -52,14 +52,10 @@ async function copyShellScripts() { } async function copyCertifi() { - await mkdir("./build/node_modules/certifi", { recursive: true }); await mkdir("./build/node_modules/certifi", { recursive: true }); await cp("./node_modules/certifi/", "./build/node_modules/certifi", { recursive: true, }); - await cp("./node_modules/node-forge/", "./build/node_modules/node-forge", { - recursive: true, - }); } async function copyAndModifyPackageJson() { const packageJsonContent = await readFile( @@ -82,7 +78,6 @@ async function copyAndModifyPackageJson() { outputPath: "dist", assets: [ "node_modules/certifi/**/*", - "node_modules/node-forge/**/*", "bin/startup-scripts/**/*", "bin/path-wrappers/**/*", ], diff --git a/packages/safe-chain/src/registryProxy/certUtils.js b/packages/safe-chain/src/registryProxy/certUtils.js index 6b326c8..178f764 100644 --- a/packages/safe-chain/src/registryProxy/certUtils.js +++ b/packages/safe-chain/src/registryProxy/certUtils.js @@ -3,6 +3,9 @@ import path from "path"; import fs from "fs"; import os from "os"; +// @ts-ignore +forge.options.usePureJavaScript = true; + const certFolder = path.join(os.homedir(), ".safe-chain", "certs"); const ca = loadCa(); From 51616dda777c3a3acfdeb6a1ac608e1668039b42 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 15:23:52 +0100 Subject: [PATCH 28/86] Comment out cert generation --- .../src/registryProxy/certBundle.js | 8 +- .../safe-chain/src/registryProxy/certUtils.js | 106 +++++++++--------- 2 files changed, 57 insertions(+), 57 deletions(-) diff --git a/packages/safe-chain/src/registryProxy/certBundle.js b/packages/safe-chain/src/registryProxy/certBundle.js index 956279d..9b36c80 100644 --- a/packages/safe-chain/src/registryProxy/certBundle.js +++ b/packages/safe-chain/src/registryProxy/certBundle.js @@ -5,7 +5,7 @@ import path from "node:path"; import certifi from "certifi"; import tls from "node:tls"; import { X509Certificate } from "node:crypto"; -import { getCaCertPath } from "./certUtils.js"; +// import { getCaCertPath } from "./certUtils.js"; /** * Check if a PEM string contains only parsable cert blocks. @@ -58,10 +58,10 @@ export function getCombinedCaBundlePath() { const parts = []; // 1) Safe Chain CA (for MITM'd registries) - const safeChainPath = getCaCertPath(); + // const safeChainPath = getCaCertPath(); try { - const safeChainPem = fs.readFileSync(safeChainPath, "utf8"); - if (isParsable(safeChainPem)) parts.push(safeChainPem.trim()); + // const safeChainPem = fs.readFileSync(safeChainPath, "utf8"); + // if (isParsable(safeChainPem)) parts.push(safeChainPem.trim()); } catch { // Ignore if Safe Chain CA is not available } diff --git a/packages/safe-chain/src/registryProxy/certUtils.js b/packages/safe-chain/src/registryProxy/certUtils.js index 178f764..c8f46d6 100644 --- a/packages/safe-chain/src/registryProxy/certUtils.js +++ b/packages/safe-chain/src/registryProxy/certUtils.js @@ -1,13 +1,13 @@ import forge from "node-forge"; import path from "path"; -import fs from "fs"; +// import fs from "fs"; import os from "os"; // @ts-ignore forge.options.usePureJavaScript = true; const certFolder = path.join(os.homedir(), ".safe-chain", "certs"); -const ca = loadCa(); +// const ca = loadCa(); const certCache = new Map(); @@ -35,7 +35,7 @@ export function generateCertForHost(hostname) { const attrs = [{ name: "commonName", value: hostname }]; cert.setSubject(attrs); - cert.setIssuer(ca.certificate.subject.attributes); + // cert.setIssuer(ca.certificate.subject.attributes); cert.setExtensions([ { name: "subjectAltName", @@ -62,7 +62,7 @@ export function generateCertForHost(hostname) { serverAuth: true, }, ]); - cert.sign(ca.privateKey, forge.md.sha256.create()); + // cert.sign(ca.privateKey, forge.md.sha256.create()); const result = { privateKey: forge.pki.privateKeyToPem(keys.privateKey), @@ -74,58 +74,58 @@ export function generateCertForHost(hostname) { return result; } -function loadCa() { - const keyPath = path.join(certFolder, "ca-key.pem"); - const certPath = path.join(certFolder, "ca-cert.pem"); +// function loadCa() { +// const keyPath = path.join(certFolder, "ca-key.pem"); +// const certPath = path.join(certFolder, "ca-cert.pem"); - if (fs.existsSync(keyPath) && fs.existsSync(certPath)) { - const privateKeyPem = fs.readFileSync(keyPath, "utf8"); - const certPem = fs.readFileSync(certPath, "utf8"); - const privateKey = forge.pki.privateKeyFromPem(privateKeyPem); - const certificate = forge.pki.certificateFromPem(certPem); +// if (fs.existsSync(keyPath) && fs.existsSync(certPath)) { +// const privateKeyPem = fs.readFileSync(keyPath, "utf8"); +// const certPem = fs.readFileSync(certPath, "utf8"); +// const privateKey = forge.pki.privateKeyFromPem(privateKeyPem); +// const certificate = forge.pki.certificateFromPem(certPem); - // Don't return a cert that is valid for less than 1 hour - const oneHourFromNow = new Date(Date.now() + 60 * 60 * 1000); - if (certificate.validity.notAfter > oneHourFromNow) { - return { privateKey, certificate }; - } - } +// // Don't return a cert that is valid for less than 1 hour +// const oneHourFromNow = new Date(Date.now() + 60 * 60 * 1000); +// if (certificate.validity.notAfter > oneHourFromNow) { +// return { privateKey, certificate }; +// } +// } - const { privateKey, certificate } = generateCa(); - fs.mkdirSync(certFolder, { recursive: true }); - fs.writeFileSync(keyPath, forge.pki.privateKeyToPem(privateKey)); - fs.writeFileSync(certPath, forge.pki.certificateToPem(certificate)); - return { privateKey, certificate }; -} +// const { privateKey, certificate } = generateCa(); +// fs.mkdirSync(certFolder, { recursive: true }); +// fs.writeFileSync(keyPath, forge.pki.privateKeyToPem(privateKey)); +// fs.writeFileSync(certPath, forge.pki.certificateToPem(certificate)); +// return { privateKey, certificate }; +// } -function generateCa() { - const keys = forge.pki.rsa.generateKeyPair(2048); - const cert = forge.pki.createCertificate(); - cert.publicKey = keys.publicKey; - cert.serialNumber = "01"; - cert.validity.notBefore = new Date(); - cert.validity.notAfter = new Date(); - cert.validity.notAfter.setDate(cert.validity.notBefore.getDate() + 1); +// function generateCa() { +// const keys = forge.pki.rsa.generateKeyPair(2048); +// const cert = forge.pki.createCertificate(); +// cert.publicKey = keys.publicKey; +// cert.serialNumber = "01"; +// cert.validity.notBefore = new Date(); +// cert.validity.notAfter = new Date(); +// cert.validity.notAfter.setDate(cert.validity.notBefore.getDate() + 1); - const attrs = [{ name: "commonName", value: "safe-chain proxy" }]; - cert.setSubject(attrs); - cert.setIssuer(attrs); - cert.setExtensions([ - { - name: "basicConstraints", - cA: true, - }, - { - name: "keyUsage", - keyCertSign: true, - digitalSignature: true, - keyEncipherment: true, - }, - ]); - cert.sign(keys.privateKey, forge.md.sha256.create()); +// const attrs = [{ name: "commonName", value: "safe-chain proxy" }]; +// cert.setSubject(attrs); +// cert.setIssuer(attrs); +// cert.setExtensions([ +// { +// name: "basicConstraints", +// cA: true, +// }, +// { +// name: "keyUsage", +// keyCertSign: true, +// digitalSignature: true, +// keyEncipherment: true, +// }, +// ]); +// cert.sign(keys.privateKey, forge.md.sha256.create()); - return { - privateKey: keys.privateKey, - certificate: cert, - }; -} +// return { +// privateKey: keys.privateKey, +// certificate: cert, +// }; +// } From 8ab4d2955a28a322bc95cc24410aa9ca686badb5 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 15:27:40 +0100 Subject: [PATCH 29/86] Add debug logs --- .../safe-chain/src/registryProxy/certUtils.js | 111 +++++++++--------- 1 file changed, 58 insertions(+), 53 deletions(-) diff --git a/packages/safe-chain/src/registryProxy/certUtils.js b/packages/safe-chain/src/registryProxy/certUtils.js index c8f46d6..cb69473 100644 --- a/packages/safe-chain/src/registryProxy/certUtils.js +++ b/packages/safe-chain/src/registryProxy/certUtils.js @@ -1,13 +1,14 @@ import forge from "node-forge"; import path from "path"; -// import fs from "fs"; +import fs from "fs"; import os from "os"; +import { ui } from "../environment/userInteraction.js"; // @ts-ignore forge.options.usePureJavaScript = true; const certFolder = path.join(os.homedir(), ".safe-chain", "certs"); -// const ca = loadCa(); +const ca = loadCa(); const certCache = new Map(); @@ -35,7 +36,7 @@ export function generateCertForHost(hostname) { const attrs = [{ name: "commonName", value: hostname }]; cert.setSubject(attrs); - // cert.setIssuer(ca.certificate.subject.attributes); + cert.setIssuer(ca.certificate.subject.attributes); cert.setExtensions([ { name: "subjectAltName", @@ -62,7 +63,7 @@ export function generateCertForHost(hostname) { serverAuth: true, }, ]); - // cert.sign(ca.privateKey, forge.md.sha256.create()); + cert.sign(ca.privateKey, forge.md.sha256.create()); const result = { privateKey: forge.pki.privateKeyToPem(keys.privateKey), @@ -74,58 +75,62 @@ export function generateCertForHost(hostname) { return result; } -// function loadCa() { -// const keyPath = path.join(certFolder, "ca-key.pem"); -// const certPath = path.join(certFolder, "ca-cert.pem"); +function loadCa() { + const keyPath = path.join(certFolder, "ca-key.pem"); + const certPath = path.join(certFolder, "ca-cert.pem"); -// if (fs.existsSync(keyPath) && fs.existsSync(certPath)) { -// const privateKeyPem = fs.readFileSync(keyPath, "utf8"); -// const certPem = fs.readFileSync(certPath, "utf8"); -// const privateKey = forge.pki.privateKeyFromPem(privateKeyPem); -// const certificate = forge.pki.certificateFromPem(certPem); + if (fs.existsSync(keyPath) && fs.existsSync(certPath)) { + const privateKeyPem = fs.readFileSync(keyPath, "utf8"); + const certPem = fs.readFileSync(certPath, "utf8"); + const privateKey = forge.pki.privateKeyFromPem(privateKeyPem); + const certificate = forge.pki.certificateFromPem(certPem); -// // Don't return a cert that is valid for less than 1 hour -// const oneHourFromNow = new Date(Date.now() + 60 * 60 * 1000); -// if (certificate.validity.notAfter > oneHourFromNow) { -// return { privateKey, certificate }; -// } -// } + // Don't return a cert that is valid for less than 1 hour + const oneHourFromNow = new Date(Date.now() + 60 * 60 * 1000); + if (certificate.validity.notAfter > oneHourFromNow) { + return { privateKey, certificate }; + } + } -// const { privateKey, certificate } = generateCa(); -// fs.mkdirSync(certFolder, { recursive: true }); -// fs.writeFileSync(keyPath, forge.pki.privateKeyToPem(privateKey)); -// fs.writeFileSync(certPath, forge.pki.certificateToPem(certificate)); -// return { privateKey, certificate }; -// } + const { privateKey, certificate } = generateCa(); + fs.mkdirSync(certFolder, { recursive: true }); + fs.writeFileSync(keyPath, forge.pki.privateKeyToPem(privateKey)); + fs.writeFileSync(certPath, forge.pki.certificateToPem(certificate)); + return { privateKey, certificate }; +} -// function generateCa() { -// const keys = forge.pki.rsa.generateKeyPair(2048); -// const cert = forge.pki.createCertificate(); -// cert.publicKey = keys.publicKey; -// cert.serialNumber = "01"; -// cert.validity.notBefore = new Date(); -// cert.validity.notAfter = new Date(); -// cert.validity.notAfter.setDate(cert.validity.notBefore.getDate() + 1); +function generateCa() { + ui.writeInformation("1"); + const keys = forge.pki.rsa.generateKeyPair(2048); + ui.writeInformation("2"); + const cert = forge.pki.createCertificate(); + ui.writeInformation("3"); + cert.publicKey = keys.publicKey; + cert.serialNumber = "01"; + cert.validity.notBefore = new Date(); + cert.validity.notAfter = new Date(); + cert.validity.notAfter.setDate(cert.validity.notBefore.getDate() + 1); -// const attrs = [{ name: "commonName", value: "safe-chain proxy" }]; -// cert.setSubject(attrs); -// cert.setIssuer(attrs); -// cert.setExtensions([ -// { -// name: "basicConstraints", -// cA: true, -// }, -// { -// name: "keyUsage", -// keyCertSign: true, -// digitalSignature: true, -// keyEncipherment: true, -// }, -// ]); -// cert.sign(keys.privateKey, forge.md.sha256.create()); + const attrs = [{ name: "commonName", value: "safe-chain proxy" }]; + cert.setSubject(attrs); + cert.setIssuer(attrs); + cert.setExtensions([ + { + name: "basicConstraints", + cA: true, + }, + { + name: "keyUsage", + keyCertSign: true, + digitalSignature: true, + keyEncipherment: true, + }, + ]); + cert.sign(keys.privateKey, forge.md.sha256.create()); + ui.writeInformation("4"); -// return { -// privateKey: keys.privateKey, -// certificate: cert, -// }; -// } + return { + privateKey: keys.privateKey, + certificate: cert, + }; +} From 20420f865e6d20b956f103d437f8626aae85f6ed Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 15:32:52 +0100 Subject: [PATCH 30/86] Try set pure javascript for node-forge --- build.js | 12 ++++++++++++ packages/safe-chain/src/registryProxy/certBundle.js | 8 ++++---- packages/safe-chain/src/registryProxy/certUtils.js | 3 --- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/build.js b/build.js index e576c5a..667e2ed 100644 --- a/build.js +++ b/build.js @@ -26,6 +26,15 @@ async function clearOutputFolder() { } async function bundleSafeChain() { + // Read the forge.js file and modify it to use pure JavaScript + const forgeContent = await readFile("./node_modules/node-forge/lib/forge.js", "utf-8"); + const modifiedForge = forgeContent.replace( + "usePureJavaScript: false", + "usePureJavaScript: true" + ); + await mkdir("./build/temp", { recursive: true }); + await writeFile("./build/temp/forge.js", modifiedForge); + await build({ entryPoints: ["./packages/safe-chain/bin/safe-chain.js"], bundle: true, @@ -33,6 +42,9 @@ async function bundleSafeChain() { target: "node24", outfile: "./build/bin/safe-chain.cjs", external: ["certifi"], + alias: { + "node-forge/lib/forge": "./build/temp/forge.js", + }, }); } diff --git a/packages/safe-chain/src/registryProxy/certBundle.js b/packages/safe-chain/src/registryProxy/certBundle.js index 9b36c80..956279d 100644 --- a/packages/safe-chain/src/registryProxy/certBundle.js +++ b/packages/safe-chain/src/registryProxy/certBundle.js @@ -5,7 +5,7 @@ import path from "node:path"; import certifi from "certifi"; import tls from "node:tls"; import { X509Certificate } from "node:crypto"; -// import { getCaCertPath } from "./certUtils.js"; +import { getCaCertPath } from "./certUtils.js"; /** * Check if a PEM string contains only parsable cert blocks. @@ -58,10 +58,10 @@ export function getCombinedCaBundlePath() { const parts = []; // 1) Safe Chain CA (for MITM'd registries) - // const safeChainPath = getCaCertPath(); + const safeChainPath = getCaCertPath(); try { - // const safeChainPem = fs.readFileSync(safeChainPath, "utf8"); - // if (isParsable(safeChainPem)) parts.push(safeChainPem.trim()); + const safeChainPem = fs.readFileSync(safeChainPath, "utf8"); + if (isParsable(safeChainPem)) parts.push(safeChainPem.trim()); } catch { // Ignore if Safe Chain CA is not available } diff --git a/packages/safe-chain/src/registryProxy/certUtils.js b/packages/safe-chain/src/registryProxy/certUtils.js index cb69473..02a0f53 100644 --- a/packages/safe-chain/src/registryProxy/certUtils.js +++ b/packages/safe-chain/src/registryProxy/certUtils.js @@ -4,9 +4,6 @@ import fs from "fs"; import os from "os"; import { ui } from "../environment/userInteraction.js"; -// @ts-ignore -forge.options.usePureJavaScript = true; - const certFolder = path.join(os.homedir(), ".safe-chain", "certs"); const ca = loadCa(); From 95d436100db9f7911f05b51c87ff47b0cce986ae Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 15:40:50 +0100 Subject: [PATCH 31/86] Again, try pure javascript --- build.js | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/build.js b/build.js index 667e2ed..ecc49e7 100644 --- a/build.js +++ b/build.js @@ -26,15 +26,6 @@ async function clearOutputFolder() { } async function bundleSafeChain() { - // Read the forge.js file and modify it to use pure JavaScript - const forgeContent = await readFile("./node_modules/node-forge/lib/forge.js", "utf-8"); - const modifiedForge = forgeContent.replace( - "usePureJavaScript: false", - "usePureJavaScript: true" - ); - await mkdir("./build/temp", { recursive: true }); - await writeFile("./build/temp/forge.js", modifiedForge); - await build({ entryPoints: ["./packages/safe-chain/bin/safe-chain.js"], bundle: true, @@ -42,10 +33,17 @@ async function bundleSafeChain() { target: "node24", outfile: "./build/bin/safe-chain.cjs", external: ["certifi"], - alias: { - "node-forge/lib/forge": "./build/temp/forge.js", - }, }); + + // Post-process: Replace all usePureJavaScript: false with true + // This ensures node-forge uses pure JavaScript crypto instead of native bindings + // which prevents segmentation faults in pkg binaries on Linux + let bundledContent = await readFile("./build/bin/safe-chain.cjs", "utf-8"); + bundledContent = bundledContent.replace( + /usePureJavaScript:\s*false/g, + "usePureJavaScript: true" + ); + await writeFile("./build/bin/safe-chain.cjs", bundledContent); } async function copyShellScripts() { From ae9bc8a75dab012f18be9cb4b607221b20e89f7d Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 15:44:45 +0100 Subject: [PATCH 32/86] Try to get it to work :/ --- build.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/build.js b/build.js index ecc49e7..9cb8ca5 100644 --- a/build.js +++ b/build.js @@ -35,14 +35,25 @@ async function bundleSafeChain() { external: ["certifi"], }); - // Post-process: Replace all usePureJavaScript: false with true - // This ensures node-forge uses pure JavaScript crypto instead of native bindings - // which prevents segmentation faults in pkg binaries on Linux + // Post-process: Force node-forge to use pure JavaScript + // This prevents segmentation faults in pkg binaries on Linux let bundledContent = await readFile("./build/bin/safe-chain.cjs", "utf-8"); + + // 1. Set the option to true bundledContent = bundledContent.replace( /usePureJavaScript:\s*false/g, "usePureJavaScript: true" ); + + // 2. Replace all checks that would enable native crypto + // Change: if (!forge2.options.usePureJavaScript && ...) + // To: if (false && ...) + // This makes the native crypto branches unreachable + bundledContent = bundledContent.replace( + /!forge2\.options\.usePureJavaScript/g, + "false" + ); + await writeFile("./build/bin/safe-chain.cjs", bundledContent); } From 35ab58c440125182bcb6fd46e1ba854047840914 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 15:53:38 +0100 Subject: [PATCH 33/86] Try package downgrade --- build.js | 17 ----------------- package-lock.json | 20 ++++++++++---------- packages/safe-chain/package.json | 2 +- 3 files changed, 11 insertions(+), 28 deletions(-) diff --git a/build.js b/build.js index 9cb8ca5..24230cd 100644 --- a/build.js +++ b/build.js @@ -35,25 +35,8 @@ async function bundleSafeChain() { external: ["certifi"], }); - // Post-process: Force node-forge to use pure JavaScript - // This prevents segmentation faults in pkg binaries on Linux let bundledContent = await readFile("./build/bin/safe-chain.cjs", "utf-8"); - // 1. Set the option to true - bundledContent = bundledContent.replace( - /usePureJavaScript:\s*false/g, - "usePureJavaScript: true" - ); - - // 2. Replace all checks that would enable native crypto - // Change: if (!forge2.options.usePureJavaScript && ...) - // To: if (false && ...) - // This makes the native crypto branches unreachable - bundledContent = bundledContent.replace( - /!forge2\.options\.usePureJavaScript/g, - "false" - ); - await writeFile("./build/bin/safe-chain.cjs", bundledContent); } diff --git a/package-lock.json b/package-lock.json index 16f42c7..b13d6d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1402,15 +1402,6 @@ "node": ">= 0.6" } }, - "node_modules/node-forge": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.2.tgz", - "integrity": "sha512-6xKiQ+cph9KImrRh0VsjH2d8/GXA4FIMlgU4B757iI1ApvcyA9VlouP0yZJha01V+huImO+kKMU7ih+2+E14fw==", - "license": "(BSD-3-Clause OR GPL-2.0)", - "engines": { - "node": ">= 6.13.0" - } - }, "node_modules/node-pty": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.0.0.tgz", @@ -1685,7 +1676,7 @@ "https-proxy-agent": "7.0.6", "ini": "6.0.0", "make-fetch-happen": "15.0.3", - "node-forge": "1.3.2", + "node-forge": "1.3.1", "npm-registry-fetch": "19.1.1", "semver": "7.7.2" }, @@ -1724,6 +1715,15 @@ "undici-types": "~5.26.4" } }, + "packages/safe-chain/node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "license": "(BSD-3-Clause OR GPL-2.0)", + "engines": { + "node": ">= 6.13.0" + } + }, "packages/safe-chain/node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", diff --git a/packages/safe-chain/package.json b/packages/safe-chain/package.json index d35f4fc..b37c8fa 100644 --- a/packages/safe-chain/package.json +++ b/packages/safe-chain/package.json @@ -41,7 +41,7 @@ "https-proxy-agent": "7.0.6", "ini": "6.0.0", "make-fetch-happen": "15.0.3", - "node-forge": "1.3.2", + "node-forge": "1.3.1", "npm-registry-fetch": "19.1.1", "semver": "7.7.2" }, From 3add7aa25e7fe931b8e26e1cc3c30b45d0a69486 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 16:26:31 +0100 Subject: [PATCH 34/86] Remove debugging from certUtils.js --- packages/safe-chain/src/registryProxy/certUtils.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/safe-chain/src/registryProxy/certUtils.js b/packages/safe-chain/src/registryProxy/certUtils.js index 02a0f53..e148711 100644 --- a/packages/safe-chain/src/registryProxy/certUtils.js +++ b/packages/safe-chain/src/registryProxy/certUtils.js @@ -97,11 +97,8 @@ function loadCa() { } function generateCa() { - ui.writeInformation("1"); const keys = forge.pki.rsa.generateKeyPair(2048); - ui.writeInformation("2"); const cert = forge.pki.createCertificate(); - ui.writeInformation("3"); cert.publicKey = keys.publicKey; cert.serialNumber = "01"; cert.validity.notBefore = new Date(); @@ -124,7 +121,6 @@ function generateCa() { }, ]); cert.sign(keys.privateKey, forge.md.sha256.create()); - ui.writeInformation("4"); return { privateKey: keys.privateKey, From 8d82d4d56fdef6f8720702d6e984274630d7026e Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 16:28:45 +0100 Subject: [PATCH 35/86] Clean up the PR --- packages/safe-chain/package.json | 22 ------------------- .../safe-chain/src/registryProxy/certUtils.js | 1 - 2 files changed, 23 deletions(-) diff --git a/packages/safe-chain/package.json b/packages/safe-chain/package.json index b37c8fa..516077d 100644 --- a/packages/safe-chain/package.json +++ b/packages/safe-chain/package.json @@ -64,27 +64,5 @@ "type": "git", "url": "git+https://github.com/AikidoSec/safe-chain.git", "directory": "packages/safe-chain" - }, - "pkg": { - "targets": [ - "node22-linux-x64", - "node22-linux-arm64", - "node22-macos-x64", - "node22-macos-arm64", - "node22-win-x64", - "node22-win-arm64" - ], - "outputPath": "dist", - "assets": [ - "node_modules/certifi/**/*" - ], - "scripts": [ - "src/**/*.js", - "bin/**/*.js" - ], - "ignore": [ - "**/*.spec.js", - "test/**" - ] } } diff --git a/packages/safe-chain/src/registryProxy/certUtils.js b/packages/safe-chain/src/registryProxy/certUtils.js index e148711..6b326c8 100644 --- a/packages/safe-chain/src/registryProxy/certUtils.js +++ b/packages/safe-chain/src/registryProxy/certUtils.js @@ -2,7 +2,6 @@ import forge from "node-forge"; import path from "path"; import fs from "fs"; import os from "os"; -import { ui } from "../environment/userInteraction.js"; const certFolder = path.join(os.homedir(), ".safe-chain", "certs"); const ca = loadCa(); From 552fd37294a3fcad8fae4d9c580cd78761a59f32 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 16:30:18 +0100 Subject: [PATCH 36/86] Remove certificate command --- packages/safe-chain/bin/safe-chain.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/safe-chain/bin/safe-chain.js b/packages/safe-chain/bin/safe-chain.js index 90d95cf..3f32bff 100755 --- a/packages/safe-chain/bin/safe-chain.js +++ b/packages/safe-chain/bin/safe-chain.js @@ -12,7 +12,6 @@ import { main } from "../src/main.js"; import path from "path"; import { fileURLToPath } from "url"; import fs from "fs"; -import { getCombinedCaBundlePath } from "../src/registryProxy/certBundle.js"; /** @type {string} */ let dirname; @@ -57,12 +56,6 @@ if (pkgManagerCommands.includes(command)) { process.exit(0); } else if (command === "setup") { setup(); -} else if (command === "certificate") { - (async function () { - const path = getCombinedCaBundlePath(); - const data = await fs.promises.readFile(path); - ui.writeInformation(data.toString("utf8")); - })(); } else if (command === "teardown") { teardown(); } else if (command === "setup-ci") { From ab446e081d31fc159580ea71d6f4d214f018007c Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 16:33:09 +0100 Subject: [PATCH 37/86] Restore fork --- package-lock.json | 20 ++++++++++---------- packages/safe-chain/package.json | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index b13d6d3..16f42c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1402,6 +1402,15 @@ "node": ">= 0.6" } }, + "node_modules/node-forge": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.2.tgz", + "integrity": "sha512-6xKiQ+cph9KImrRh0VsjH2d8/GXA4FIMlgU4B757iI1ApvcyA9VlouP0yZJha01V+huImO+kKMU7ih+2+E14fw==", + "license": "(BSD-3-Clause OR GPL-2.0)", + "engines": { + "node": ">= 6.13.0" + } + }, "node_modules/node-pty": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.0.0.tgz", @@ -1676,7 +1685,7 @@ "https-proxy-agent": "7.0.6", "ini": "6.0.0", "make-fetch-happen": "15.0.3", - "node-forge": "1.3.1", + "node-forge": "1.3.2", "npm-registry-fetch": "19.1.1", "semver": "7.7.2" }, @@ -1715,15 +1724,6 @@ "undici-types": "~5.26.4" } }, - "packages/safe-chain/node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", - "license": "(BSD-3-Clause OR GPL-2.0)", - "engines": { - "node": ">= 6.13.0" - } - }, "packages/safe-chain/node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", diff --git a/packages/safe-chain/package.json b/packages/safe-chain/package.json index 516077d..5353635 100644 --- a/packages/safe-chain/package.json +++ b/packages/safe-chain/package.json @@ -41,7 +41,7 @@ "https-proxy-agent": "7.0.6", "ini": "6.0.0", "make-fetch-happen": "15.0.3", - "node-forge": "1.3.1", + "node-forge": "1.3.2", "npm-registry-fetch": "19.1.1", "semver": "7.7.2" }, From 3af8b694fe248a73f909c18d9c4cadfa232e8077 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 16:36:33 +0100 Subject: [PATCH 38/86] Linux arm64: use node 20 --- .github/workflows/create-artifact.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/create-artifact.yml b/.github/workflows/create-artifact.yml index 6d479c7..bda119c 100644 --- a/.github/workflows/create-artifact.yml +++ b/.github/workflows/create-artifact.yml @@ -30,7 +30,7 @@ jobs: - os: linux arch: arm64 runner: ubuntu-24.04-arm - target: node24-linux-arm64 + target: node20-linux-arm64 extension: "" - os: win arch: x64 From edec6ec57c81d77f0a630730b831c6c5738e4b93 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 16:51:39 +0100 Subject: [PATCH 39/86] Update shell scripts --- .github/workflows/create-artifact.yml | 12 +++--- .../include-python/init-fish.fish | 40 ++++++++++--------- .../include-python/init-posix.sh | 35 ++++++++-------- .../include-python/init-pwsh.ps1 | 2 + .../startup-scripts/init-fish.fish | 2 + .../startup-scripts/init-posix.sh | 1 + .../startup-scripts/init-pwsh.ps1 | 2 + 7 files changed, 50 insertions(+), 44 deletions(-) diff --git a/.github/workflows/create-artifact.yml b/.github/workflows/create-artifact.yml index bda119c..e5be214 100644 --- a/.github/workflows/create-artifact.yml +++ b/.github/workflows/create-artifact.yml @@ -15,17 +15,17 @@ jobs: - os: macos arch: x64 runner: macos-15-intel - target: node24-macos-x64 + target: node20-macos-x64 extension: "" - os: macos arch: arm64 runner: macos-latest - target: node24-macos-arm64 + target: node20-macos-arm64 extension: "" - os: linux arch: x64 runner: ubuntu-latest - target: node24-linux-x64 + target: node20-linux-x64 extension: "" - os: linux arch: arm64 @@ -35,12 +35,12 @@ jobs: - os: win arch: x64 runner: windows-latest - target: node24-win-x64 + target: node20-win-x64 extension: ".exe" - os: win arch: arm64 runner: windows-11-arm - target: node24-win-arm64 + target: node20-win-arm64 extension: ".exe" steps: @@ -50,7 +50,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v3 with: - node-version: "24.x" + node-version: "20.x" - name: Setup safe-chain run: | diff --git a/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-fish.fish b/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-fish.fish index 235ecb8..81e28ef 100644 --- a/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-fish.fish +++ b/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-fish.fish @@ -1,3 +1,5 @@ +set -gx PATH $PATH $HOME/.safe-chain/bin + function printSafeChainWarning set original_cmd $argv[1] @@ -17,41 +19,40 @@ end function wrapSafeChainCommand set original_cmd $argv[1] - set aikido_cmd $argv[2] - set cmd_args $argv[3..-1] - - if type -q $aikido_cmd - # If the aikido command is available, just run it with the provided arguments - $aikido_cmd $cmd_args + set cmd_args $argv[2..-1] + + if type -q safe-chain + # If the safe-chain command is available, just run it with the provided arguments + safe-chain $original_cmd $cmd_args else - # If the aikido command is not available, print a warning and run the original command + # If the safe-chain command is not available, print a warning and run the original command printSafeChainWarning $original_cmd command $original_cmd $cmd_args end end function npx - wrapSafeChainCommand "npx" "aikido-npx" $argv + wrapSafeChainCommand "npx" $argv end function yarn - wrapSafeChainCommand "yarn" "aikido-yarn" $argv + wrapSafeChainCommand "yarn" $argv end function pnpm - wrapSafeChainCommand "pnpm" "aikido-pnpm" $argv + wrapSafeChainCommand "pnpm" $argv end function pnpx - wrapSafeChainCommand "pnpx" "aikido-pnpx" $argv + wrapSafeChainCommand "pnpx" $argv end function bun - wrapSafeChainCommand "bun" "aikido-bun" $argv + wrapSafeChainCommand "bun" $argv end function bunx - wrapSafeChainCommand "bunx" "aikido-bunx" $argv + wrapSafeChainCommand "bunx" $argv end function npm @@ -66,27 +67,28 @@ function npm end end - wrapSafeChainCommand "npm" "aikido-npm" $argv + wrapSafeChainCommand "npm" $argv end + function pip - wrapSafeChainCommand "pip" "aikido-pip" $argv + wrapSafeChainCommand "pip" $argv end function pip3 - wrapSafeChainCommand "pip3" "aikido-pip3" $argv + wrapSafeChainCommand "pip3" $argv end function uv - wrapSafeChainCommand "uv" "aikido-uv" $argv + wrapSafeChainCommand "uv" $argv end # `python -m pip`, `python -m pip3`. function python - wrapSafeChainCommand "python" "aikido-python" $argv + wrapSafeChainCommand "python" $argv end # `python3 -m pip`, `python3 -m pip3'. function python3 - wrapSafeChainCommand "python3" "aikido-python3" $argv + wrapSafeChainCommand "python3" $argv end diff --git a/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-posix.sh b/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-posix.sh index 9f51010..fd844fc 100644 --- a/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-posix.sh +++ b/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-posix.sh @@ -1,3 +1,4 @@ +export PATH="$PATH:$HOME/.safe-chain/bin" function printSafeChainWarning() { # \033[43;30m is used to set the background color to yellow and text color to black @@ -9,15 +10,10 @@ function printSafeChainWarning() { function wrapSafeChainCommand() { local original_cmd="$1" - local aikido_cmd="$2" - # Remove the first 2 arguments (original_cmd and aikido_cmd) from $@ - # so that "$@" now contains only the arguments passed to the original command - shift 2 - - if command -v "$aikido_cmd" > /dev/null 2>&1; then + if command -v safe-chain > /dev/null 2>&1; then # If the aikido command is available, just run it with the provided arguments - "$aikido_cmd" "$@" + safe-chain "$@" else # If the aikido command is not available, print a warning and run the original command printSafeChainWarning "$original_cmd" @@ -27,27 +23,27 @@ function wrapSafeChainCommand() { } function npx() { - wrapSafeChainCommand "npx" "aikido-npx" "$@" + wrapSafeChainCommand "npx" "$@" } function yarn() { - wrapSafeChainCommand "yarn" "aikido-yarn" "$@" + wrapSafeChainCommand "yarn" "$@" } function pnpm() { - wrapSafeChainCommand "pnpm" "aikido-pnpm" "$@" + wrapSafeChainCommand "pnpm" "$@" } function pnpx() { - wrapSafeChainCommand "pnpx" "aikido-pnpx" "$@" + wrapSafeChainCommand "pnpx" "$@" } function bun() { - wrapSafeChainCommand "bun" "aikido-bun" "$@" + wrapSafeChainCommand "bun" "$@" } function bunx() { - wrapSafeChainCommand "bunx" "aikido-bunx" "$@" + wrapSafeChainCommand "bunx" "$@" } function npm() { @@ -58,27 +54,28 @@ function npm() { return fi - wrapSafeChainCommand "npm" "aikido-npm" "$@" + wrapSafeChainCommand "npm" "$@" } + function pip() { - wrapSafeChainCommand "pip" "aikido-pip" "$@" + wrapSafeChainCommand "pip" "$@" } function pip3() { - wrapSafeChainCommand "pip3" "aikido-pip3" "$@" + wrapSafeChainCommand "pip3" "$@" } function uv() { - wrapSafeChainCommand "uv" "aikido-uv" "$@" + wrapSafeChainCommand "uv" "$@" } # `python -m pip`, `python -m pip3`. function python() { - wrapSafeChainCommand "python" "aikido-python" "$@" + wrapSafeChainCommand "python" "$@" } # `python3 -m pip`, `python3 -m pip3'. function python3() { - wrapSafeChainCommand "python3" "aikido-python3" "$@" + wrapSafeChainCommand "python3" "$@" } diff --git a/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-pwsh.ps1 b/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-pwsh.ps1 index deb127d..27a5065 100644 --- a/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-pwsh.ps1 +++ b/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-pwsh.ps1 @@ -1,3 +1,5 @@ +$env:PATH = "$env:PATH;$HOME/.safe-chain/bin" + function Write-SafeChainWarning { param([string]$Command) diff --git a/packages/safe-chain/src/shell-integration/startup-scripts/init-fish.fish b/packages/safe-chain/src/shell-integration/startup-scripts/init-fish.fish index a72380f..f697da2 100644 --- a/packages/safe-chain/src/shell-integration/startup-scripts/init-fish.fish +++ b/packages/safe-chain/src/shell-integration/startup-scripts/init-fish.fish @@ -1,3 +1,5 @@ +set -gx PATH $PATH $HOME/.safe-chain/bin + function printSafeChainWarning set original_cmd $argv[1] diff --git a/packages/safe-chain/src/shell-integration/startup-scripts/init-posix.sh b/packages/safe-chain/src/shell-integration/startup-scripts/init-posix.sh index a83e749..6d426c5 100644 --- a/packages/safe-chain/src/shell-integration/startup-scripts/init-posix.sh +++ b/packages/safe-chain/src/shell-integration/startup-scripts/init-posix.sh @@ -1,3 +1,4 @@ +export PATH="$PATH:$HOME/.safe-chain/bin" function printSafeChainWarning() { # \033[43;30m is used to set the background color to yellow and text color to black diff --git a/packages/safe-chain/src/shell-integration/startup-scripts/init-pwsh.ps1 b/packages/safe-chain/src/shell-integration/startup-scripts/init-pwsh.ps1 index 2106cac..17ddeb2 100644 --- a/packages/safe-chain/src/shell-integration/startup-scripts/init-pwsh.ps1 +++ b/packages/safe-chain/src/shell-integration/startup-scripts/init-pwsh.ps1 @@ -1,3 +1,5 @@ +$env:PATH = "$env:PATH;$HOME/.safe-chain/bin" + function Write-SafeChainWarning { param([string]$Command) From 8852afb5faf4665d08a227d625190db0c0a8bcb4 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 18:05:09 +0100 Subject: [PATCH 40/86] Fix e2e tests --- packages/safe-chain/bin/safe-chain.js | 73 +++++++++++++--- .../src/shell-integration/helpers.js | 85 ++++++++++++++++--- 2 files changed, 132 insertions(+), 26 deletions(-) diff --git a/packages/safe-chain/bin/safe-chain.js b/packages/safe-chain/bin/safe-chain.js index 3f32bff..a9a9ed3 100755 --- a/packages/safe-chain/bin/safe-chain.js +++ b/packages/safe-chain/bin/safe-chain.js @@ -6,12 +6,18 @@ import { setup } from "../src/shell-integration/setup.js"; import { teardown } from "../src/shell-integration/teardown.js"; import { setupCi } from "../src/shell-integration/setup-ci.js"; import { initializeCliArguments } from "../src/config/cliArguments.js"; -import { ECOSYSTEM_JS, setEcoSystem } from "../src/config/settings.js"; +import { setEcoSystem } from "../src/config/settings.js"; import { initializePackageManager } from "../src/packagemanager/currentPackageManager.js"; import { main } from "../src/main.js"; import path from "path"; import { fileURLToPath } from "url"; import fs from "fs"; +import { knownAikidoTools } from "../src/shell-integration/helpers.js"; +import { + PIP_INVOCATIONS, + PIP_PACKAGE_MANAGER, + setCurrentPipInvocation, +} from "../src/packagemanager/pip/pipSettings.js"; /** @type {string} */ let dirname; @@ -34,21 +40,18 @@ initializeCliArguments(process.argv); const command = process.argv[2]; -const pkgManagerCommands = [ - "npm", - "npx", - "yarn", - "bun", - "bunx", - "pnpm", - "pnpx", -]; +const tool = knownAikidoTools.find((tool) => tool.tool === command); + +if (tool && tool.internalPackageManagerName === PIP_PACKAGE_MANAGER) { + await executePip(tool); +} else if (tool) { + const args = process.argv.slice(3); + + setEcoSystem(tool.ecoSystem); + initializePackageManager(tool.internalPackageManagerName); -if (pkgManagerCommands.includes(command)) { - setEcoSystem(ECOSYSTEM_JS); - initializePackageManager(command); (async () => { - var exitCode = await main(process.argv.slice(3)); + var exitCode = await main(args); process.exit(exitCode); })(); } else if (command === "help" || command === "--help" || command === "-h") { @@ -131,3 +134,45 @@ async function getVersion() { return "1.0.0"; } + +/** + * @param {import("../src/shell-integration/helpers.js").AikidoTool} tool + */ +async function executePip(tool) { + let args = process.argv.slice(3); + setEcoSystem(tool.ecoSystem); + initializePackageManager(PIP_PACKAGE_MANAGER); + + let shouldSkip = false; + if (tool.tool === "pip") { + setCurrentPipInvocation(PIP_INVOCATIONS.PIP); + } else if (tool.tool === "pip3") { + setCurrentPipInvocation(PIP_INVOCATIONS.PIP3); + } else if (tool.tool === "python") { + if (args[0] === "-m" && (args[1] === "pip" || args[1] === "pip3")) { + setCurrentPipInvocation( + args[1] === "pip3" ? PIP_INVOCATIONS.PY_PIP3 : PIP_INVOCATIONS.PY_PIP + ); + args = args.slice(2); + } else { + shouldSkip = true; + } + } else if (tool.tool === "python3") { + if (args[0] === "-m" && (args[1] === "pip" || args[1] === "pip3")) { + setCurrentPipInvocation( + args[1] === "pip3" ? PIP_INVOCATIONS.PY3_PIP3 : PIP_INVOCATIONS.PY3_PIP + ); + args = args.slice(2); + } else { + shouldSkip = true; + } + } + + if (shouldSkip) { + const { spawn } = await import("child_process"); + spawn(tool.tool, args, { stdio: "inherit" }); + } else { + var exitCode = await main(args); + process.exit(exitCode); + } +} diff --git a/packages/safe-chain/src/shell-integration/helpers.js b/packages/safe-chain/src/shell-integration/helpers.js index 7f45669..1d32e82 100644 --- a/packages/safe-chain/src/shell-integration/helpers.js +++ b/packages/safe-chain/src/shell-integration/helpers.js @@ -9,24 +9,85 @@ import { ECOSYSTEM_JS, ECOSYSTEM_PY } from "../config/settings.js"; * @property {string} tool * @property {string} aikidoCommand * @property {string} ecoSystem + * @property {string} internalPackageManagerName */ /** * @type {AikidoTool[]} */ export const knownAikidoTools = [ - { tool: "npm", aikidoCommand: "aikido-npm", ecoSystem: ECOSYSTEM_JS }, - { tool: "npx", aikidoCommand: "aikido-npx", ecoSystem: ECOSYSTEM_JS }, - { tool: "yarn", aikidoCommand: "aikido-yarn", ecoSystem: ECOSYSTEM_JS }, - { tool: "pnpm", aikidoCommand: "aikido-pnpm", ecoSystem: ECOSYSTEM_JS }, - { tool: "pnpx", aikidoCommand: "aikido-pnpx", ecoSystem: ECOSYSTEM_JS }, - { tool: "bun", aikidoCommand: "aikido-bun", ecoSystem: ECOSYSTEM_JS }, - { tool: "bunx", aikidoCommand: "aikido-bunx", ecoSystem: ECOSYSTEM_JS }, - { tool: "uv", aikidoCommand: "aikido-uv", ecoSystem: ECOSYSTEM_PY }, - { tool: "pip", aikidoCommand: "aikido-pip", ecoSystem: ECOSYSTEM_PY }, - { tool: "pip3", aikidoCommand: "aikido-pip3", ecoSystem: ECOSYSTEM_PY }, - { tool: "python", aikidoCommand: "aikido-python", ecoSystem: ECOSYSTEM_PY }, - { tool: "python3", aikidoCommand: "aikido-python3", ecoSystem: ECOSYSTEM_PY }, + { + tool: "npm", + aikidoCommand: "aikido-npm", + ecoSystem: ECOSYSTEM_JS, + internalPackageManagerName: "npm", + }, + { + tool: "npx", + aikidoCommand: "aikido-npx", + ecoSystem: ECOSYSTEM_JS, + internalPackageManagerName: "npx", + }, + { + tool: "yarn", + aikidoCommand: "aikido-yarn", + ecoSystem: ECOSYSTEM_JS, + internalPackageManagerName: "yarn", + }, + { + tool: "pnpm", + aikidoCommand: "aikido-pnpm", + ecoSystem: ECOSYSTEM_JS, + internalPackageManagerName: "pnpm", + }, + { + tool: "pnpx", + aikidoCommand: "aikido-pnpx", + ecoSystem: ECOSYSTEM_JS, + internalPackageManagerName: "pnpx", + }, + { + tool: "bun", + aikidoCommand: "aikido-bun", + ecoSystem: ECOSYSTEM_JS, + internalPackageManagerName: "bun", + }, + { + tool: "bunx", + aikidoCommand: "aikido-bunx", + ecoSystem: ECOSYSTEM_JS, + internalPackageManagerName: "bunx", + }, + { + tool: "uv", + aikidoCommand: "aikido-uv", + ecoSystem: ECOSYSTEM_PY, + internalPackageManagerName: "uv", + }, + { + tool: "pip", + aikidoCommand: "aikido-pip", + ecoSystem: ECOSYSTEM_PY, + internalPackageManagerName: "pip", + }, + { + tool: "pip3", + aikidoCommand: "aikido-pip3", + ecoSystem: ECOSYSTEM_PY, + internalPackageManagerName: "pip", + }, + { + tool: "python", + aikidoCommand: "aikido-python", + ecoSystem: ECOSYSTEM_PY, + internalPackageManagerName: "pip", + }, + { + tool: "python3", + aikidoCommand: "aikido-python3", + ecoSystem: ECOSYSTEM_PY, + internalPackageManagerName: "pip", + }, // When adding a new tool here, also update the documentation for the new tool in the README.md ]; From 1361abc4e86a522e7a1a1e38e320e93016cf4ac2 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Fri, 28 Nov 2025 18:06:31 +0100 Subject: [PATCH 41/86] Fix top-level await --- packages/safe-chain/bin/safe-chain.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/safe-chain/bin/safe-chain.js b/packages/safe-chain/bin/safe-chain.js index a9a9ed3..0a73f0e 100755 --- a/packages/safe-chain/bin/safe-chain.js +++ b/packages/safe-chain/bin/safe-chain.js @@ -43,7 +43,9 @@ const command = process.argv[2]; const tool = knownAikidoTools.find((tool) => tool.tool === command); if (tool && tool.internalPackageManagerName === PIP_PACKAGE_MANAGER) { - await executePip(tool); + (async function () { + await executePip(tool); + })(); } else if (tool) { const args = process.argv.slice(3); From 2e57057baaf73384c57c0e05809e6c9b84bf0aac Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Mon, 1 Dec 2025 09:57:28 +0100 Subject: [PATCH 42/86] Update path wrappers --- .../path-wrappers/templates/unix-wrapper.template.sh | 4 ++-- .../path-wrappers/templates/windows-wrapper.template.cmd | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/safe-chain/src/shell-integration/path-wrappers/templates/unix-wrapper.template.sh b/packages/safe-chain/src/shell-integration/path-wrappers/templates/unix-wrapper.template.sh index e914e5b..d6c9efd 100644 --- a/packages/safe-chain/src/shell-integration/path-wrappers/templates/unix-wrapper.template.sh +++ b/packages/safe-chain/src/shell-integration/path-wrappers/templates/unix-wrapper.template.sh @@ -7,9 +7,9 @@ remove_shim_from_path() { echo "$PATH" | sed "s|$HOME/.safe-chain/shims:||g" } -if command -v {{AIKIDO_COMMAND}} >/dev/null 2>&1; then +if command -v safe-chain >/dev/null 2>&1; then # Remove shim directory from PATH when calling {{AIKIDO_COMMAND}} to prevent infinite loops - PATH=$(remove_shim_from_path) exec {{AIKIDO_COMMAND}} "$@" + PATH=$(remove_shim_from_path) exec safe-chain {{PACKAGE_MANAGER}} "$@" else # Dynamically find original {{PACKAGE_MANAGER}} (excluding this shim directory) original_cmd=$(PATH=$(remove_shim_from_path) command -v {{PACKAGE_MANAGER}}) diff --git a/packages/safe-chain/src/shell-integration/path-wrappers/templates/windows-wrapper.template.cmd b/packages/safe-chain/src/shell-integration/path-wrappers/templates/windows-wrapper.template.cmd index b7a65fa..d941a56 100644 --- a/packages/safe-chain/src/shell-integration/path-wrappers/templates/windows-wrapper.template.cmd +++ b/packages/safe-chain/src/shell-integration/path-wrappers/templates/windows-wrapper.template.cmd @@ -10,7 +10,7 @@ REM Check if aikido command is available with clean PATH set "PATH=%CLEAN_PATH%" & where {{AIKIDO_COMMAND}} >nul 2>&1 if %errorlevel%==0 ( REM Call aikido command with clean PATH - set "PATH=%CLEAN_PATH%" & {{AIKIDO_COMMAND}} %* + set "PATH=%CLEAN_PATH%" & safe-chain {{PACKAGE_MANAGER}} %* ) else ( REM Find the original command with clean PATH for /f "tokens=*" %%i in ('set "PATH=%CLEAN_PATH%" ^& where {{PACKAGE_MANAGER}} 2^>nul') do ( From 20e9826ef0259e6491c5c6b3134d4aca72201253 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Mon, 1 Dec 2025 12:31:55 +0100 Subject: [PATCH 43/86] Modify release pipeline to attach the binaries. --- .github/workflows/build-and-release.yml | 25 ++++++++++++++++++++++++- .github/workflows/create-artifact.yml | 4 +++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml index 2c1a423..e116281 100644 --- a/.github/workflows/build-and-release.yml +++ b/.github/workflows/build-and-release.yml @@ -7,10 +7,14 @@ on: permissions: id-token: write - contents: read + contents: write jobs: + create-binaries: + uses: ./.github/workflows/create-artifact.yml + build: + needs: create-binaries runs-on: ubuntu-latest steps: @@ -55,3 +59,22 @@ jobs: run: | echo "Publishing version ${{ steps.get_version.outputs.tag }} to NPM" npm publish --workspace=packages/safe-chain --access public --provenance + + - name: Download all binary artifacts + uses: actions/download-artifact@v4 + with: + path: binaries/ + pattern: safe-chain-* + merge-multiple: false + + - name: Upload binaries to existing GitHub Release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release upload ${{ steps.get_version.outputs.tag }} \ + binaries/safe-chain-macos-x64/* \ + binaries/safe-chain-macos-arm64/* \ + binaries/safe-chain-linux-x64/* \ + binaries/safe-chain-linux-arm64/* \ + binaries/safe-chain-win-x64/* \ + binaries/safe-chain-win-arm64/* diff --git a/.github/workflows/create-artifact.yml b/.github/workflows/create-artifact.yml index e5be214..7d573e5 100644 --- a/.github/workflows/create-artifact.yml +++ b/.github/workflows/create-artifact.yml @@ -1,6 +1,8 @@ name: Create binaries -on: pull_request +on: + pull_request: + workflow_call: jobs: create-binaries: From 3f60ea15f76d0d791465c31dd498219da83ebbe6 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Mon, 1 Dec 2025 13:28:11 +0100 Subject: [PATCH 44/86] Set release version on PR build --- .github/workflows/build-and-release.yml | 34 +++++++++++++++---------- .github/workflows/create-artifact.yml | 9 +++++++ 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml index e116281..e310bc5 100644 --- a/.github/workflows/build-and-release.yml +++ b/.github/workflows/build-and-release.yml @@ -10,11 +10,25 @@ permissions: contents: write jobs: + set-version: + runs-on: ubuntu-latest + outputs: + version: ${{ steps.get_version.outputs.tag }} + steps: + - name: Set version number + id: get_version + run: | + version="${{ github.ref_name }}" + echo "tag=$version" >> $GITHUB_OUTPUT + create-binaries: + needs: set-version uses: ./.github/workflows/create-artifact.yml + with: + version: ${{ needs.set-version.outputs.version }} build: - needs: create-binaries + needs: [set-version, create-binaries] runs-on: ubuntu-latest steps: @@ -34,14 +48,8 @@ jobs: npm i -g @aikidosec/safe-chain safe-chain setup-ci - - name: Set version number - id: get_version - run: | - version="${{ github.ref_name }}" - echo "tag=$version" >> $GITHUB_OUTPUT - - name: Set the version in safe-chain package - run: npm --no-git-tag-version version ${{ steps.get_version.outputs.tag }} --workspace=packages/safe-chain + run: npm --no-git-tag-version version ${{ needs.set-version.outputs.version }} --workspace=packages/safe-chain - name: Install dependencies run: npm ci @@ -55,10 +63,10 @@ jobs: cp LICENSE packages/safe-chain/ cp -r docs packages/safe-chain/ - - name: Publish to npm - run: | - echo "Publishing version ${{ steps.get_version.outputs.tag }} to NPM" - npm publish --workspace=packages/safe-chain --access public --provenance + # - name: Publish to npm + # run: | + # echo "Publishing version ${{ steps.get_version.outputs.tag }} to NPM" + # npm publish --workspace=packages/safe-chain --access public --provenance - name: Download all binary artifacts uses: actions/download-artifact@v4 @@ -71,7 +79,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - gh release upload ${{ steps.get_version.outputs.tag }} \ + gh release upload ${{ needs.set-version.outputs.version }} \ binaries/safe-chain-macos-x64/* \ binaries/safe-chain-macos-arm64/* \ binaries/safe-chain-linux-x64/* \ diff --git a/.github/workflows/create-artifact.yml b/.github/workflows/create-artifact.yml index 7d573e5..ad43a9d 100644 --- a/.github/workflows/create-artifact.yml +++ b/.github/workflows/create-artifact.yml @@ -3,6 +3,11 @@ name: Create binaries on: pull_request: workflow_call: + inputs: + version: + description: 'Version to set in package.json' + required: false + type: string jobs: create-binaries: @@ -59,6 +64,10 @@ jobs: npm i -g @aikidosec/safe-chain safe-chain setup-ci + - name: Set the version in safe-chain package + if: inputs.version != '' + run: npm --no-git-tag-version version ${{ inputs.version }} --workspace=packages/safe-chain + - name: Install dependencies run: npm ci --ignore-scripts From 6f583ce396bd6956a14502256e0c3dd94e6fdd5d Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Mon, 1 Dec 2025 14:09:05 +0100 Subject: [PATCH 45/86] Rename build artifacts --- .github/workflows/build-and-release.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml index e310bc5..4464c02 100644 --- a/.github/workflows/build-and-release.yml +++ b/.github/workflows/build-and-release.yml @@ -75,6 +75,15 @@ jobs: pattern: safe-chain-* merge-multiple: false + - name: Rename binaries to include platform and architecture + run: | + mv binaries/safe-chain-macos-x64/safe-chain binaries/safe-chain-macos-x64/safe-chain-macos-x64 + mv binaries/safe-chain-macos-arm64/safe-chain binaries/safe-chain-macos-arm64/safe-chain-macos-arm64 + mv binaries/safe-chain-linux-x64/safe-chain binaries/safe-chain-linux-x64/safe-chain-linux-x64 + mv binaries/safe-chain-linux-arm64/safe-chain binaries/safe-chain-linux-arm64/safe-chain-linux-arm64 + mv binaries/safe-chain-win-x64/safe-chain.exe binaries/safe-chain-win-x64/safe-chain-win-x64.exe + mv binaries/safe-chain-win-arm64/safe-chain.exe binaries/safe-chain-win-arm64/safe-chain-win-arm64.exe + - name: Upload binaries to existing GitHub Release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From e58e77bc6323b29b525e3d8601cc13adc42eba06 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Mon, 1 Dec 2025 14:39:41 +0100 Subject: [PATCH 46/86] Install scripts --- install-scripts/install-safe-chain.ps1 | 154 +++++++++++++++++++++++++ install-scripts/install-safe-chain.sh | 126 ++++++++++++++++++++ 2 files changed, 280 insertions(+) create mode 100644 install-scripts/install-safe-chain.ps1 create mode 100755 install-scripts/install-safe-chain.sh diff --git a/install-scripts/install-safe-chain.ps1 b/install-scripts/install-safe-chain.ps1 new file mode 100644 index 0000000..ac85891 --- /dev/null +++ b/install-scripts/install-safe-chain.ps1 @@ -0,0 +1,154 @@ +# Downloads and installs safe-chain for Windows +# Usage: iex (iwr "https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.ps1" -UseBasicParsing) + +param( + [string]$Version +) + +# Configuration +if (-not $Version) { + $Version = if ($env:SAFE_CHAIN_VERSION) { $env:SAFE_CHAIN_VERSION } else { "v0.0.2-binaries-beta" } +} + +$InstallDir = Join-Path $env:USERPROFILE ".safe-chain\bin" +$RepoUrl = "https://github.com/AikidoSec/safe-chain" + +# Ensure TLS 1.2 is enabled for downloads +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + +# Helper functions +function Write-Info { + param([string]$Message) + Write-Host "[INFO] $Message" -ForegroundColor Green +} + +function Write-Warn { + param([string]$Message) + Write-Host "[WARN] $Message" -ForegroundColor Yellow +} + +function Write-Error-Custom { + param([string]$Message) + Write-Host "[ERROR] $Message" -ForegroundColor Red + exit 1 +} + +# Detect architecture +function Get-Architecture { + $arch = $env:PROCESSOR_ARCHITECTURE + switch ($arch) { + "AMD64" { return "x64" } + "ARM64" { return "arm64" } + default { Write-Error-Custom "Unsupported architecture: $arch" } + } +} + +# Main installation +function Install-SafeChain { + Write-Info "Installing safe-chain $Version..." + + # Detect platform + $arch = Get-Architecture + $binaryName = "safe-chain-win-$arch.exe" + + Write-Info "Detected architecture: $arch" + + # Create installation directory + if (-not (Test-Path $InstallDir)) { + Write-Info "Creating installation directory: $InstallDir" + try { + New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null + } + catch { + Write-Error-Custom "Failed to create directory $InstallDir : $_" + } + } + + # Download binary + $downloadUrl = "$RepoUrl/releases/download/$Version/$binaryName" + $tempFile = Join-Path $InstallDir $binaryName + $finalFile = Join-Path $InstallDir "safe-chain.exe" + + Write-Info "Downloading from: $downloadUrl" + + try { + # Download with progress suppressed for cleaner output + $ProgressPreference = 'SilentlyContinue' + Invoke-WebRequest -Uri $downloadUrl -OutFile $tempFile -UseBasicParsing + $ProgressPreference = 'Continue' + } + catch { + Write-Error-Custom "Failed to download from $downloadUrl : $_" + } + + # Rename to final location + try { + Move-Item -Path $tempFile -Destination $finalFile -Force + } + catch { + Write-Error-Custom "Failed to move binary to $finalFile : $_" + } + + Write-Info "Binary installed to: $finalFile" + + # Check if directory is in PATH + $userPath = [Environment]::GetEnvironmentVariable("Path", "User") + if ($userPath -like "*$InstallDir*") { + Write-Info "Installation directory is already in PATH" + } + else { + Write-Warn "Installation directory is not in PATH" + Write-Host "" + Write-Warn "Would you like to add it to your PATH now? (Y/N)" + $response = Read-Host + + if ($response -eq "Y" -or $response -eq "y") { + try { + $newPath = "$userPath;$InstallDir" + [Environment]::SetEnvironmentVariable("Path", $newPath, "User") + Write-Info "Added to PATH. Please restart your terminal for changes to take effect." + } + catch { + Write-Warn "Failed to add to PATH automatically: $_" + Write-Warn "Please add the following directory to your PATH manually:" + Write-Host " $InstallDir" + } + } + else { + Write-Warn "Skipping PATH setup. Add the following directory to your PATH manually:" + Write-Host "" + Write-Host " $InstallDir" + Write-Host "" + } + } + + # Execute safe-chain setup + Write-Info "Running safe-chain setup..." + + try { + $env:Path = "$env:Path;$InstallDir" + & $finalFile setup + + if ($LASTEXITCODE -eq 0) { + Write-Info "✓ safe-chain installed and configured successfully!" + } + else { + Write-Warn "safe-chain was installed but setup encountered issues." + Write-Warn "You can run 'safe-chain setup' manually later." + } + } + catch { + Write-Warn "safe-chain was installed but setup encountered issues: $_" + Write-Warn "You can run 'safe-chain setup' manually later." + } + + Write-Info "Installation complete!" +} + +# Run installation +try { + Install-SafeChain +} +catch { + Write-Error-Custom "Installation failed: $_" +} diff --git a/install-scripts/install-safe-chain.sh b/install-scripts/install-safe-chain.sh new file mode 100755 index 0000000..37f3136 --- /dev/null +++ b/install-scripts/install-safe-chain.sh @@ -0,0 +1,126 @@ +#!/bin/sh + +# Downloads and installs safe-chain, depending on the operating system and architecture +# Usage: curl -fsSL https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh +# or: wget -qO- https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh + +set -e # Exit on error + +# Configuration +VERSION="${SAFE_CHAIN_VERSION:-v0.0.2-binaries-beta}" +INSTALL_DIR="${HOME}/.safe-chain/bin" +REPO_URL="https://github.com/AikidoSec/safe-chain" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Helper functions +info() { + printf "${GREEN}[INFO]${NC} %s\n" "$1" +} + +warn() { + printf "${YELLOW}[WARN]${NC} %s\n" "$1" +} + +error() { + printf "${RED}[ERROR]${NC} %s\n" "$1" >&2 + exit 1 +} + +# Detect OS +detect_os() { + case "$(uname -s)" in + Linux*) echo "linux" ;; + Darwin*) echo "macos" ;; + *) error "Unsupported operating system: $(uname -s)" ;; + esac +} + +# Detect architecture +detect_arch() { + case "$(uname -m)" in + x86_64|amd64) echo "x64" ;; + aarch64|arm64) echo "arm64" ;; + *) error "Unsupported architecture: $(uname -m)" ;; + esac +} + +# Check if command exists +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +# Download file +download() { + url="$1" + dest="$2" + + if command_exists curl; then + curl -fsSL "$url" -o "$dest" || error "Failed to download from $url" + elif command_exists wget; then + wget -q "$url" -O "$dest" || error "Failed to download from $url" + else + error "Neither curl nor wget found. Please install one of them." + fi +} + +# Main installation +main() { + info "Installing safe-chain ${VERSION}..." + + # Detect platform + OS=$(detect_os) + ARCH=$(detect_arch) + BINARY_NAME="safe-chain-${OS}-${ARCH}" + + info "Detected platform: ${OS}-${ARCH}" + + # Create installation directory + if [ ! -d "$INSTALL_DIR" ]; then + info "Creating installation directory: $INSTALL_DIR" + mkdir -p "$INSTALL_DIR" || error "Failed to create directory $INSTALL_DIR" + fi + + # Download binary + DOWNLOAD_URL="${REPO_URL}/releases/download/${VERSION}/${BINARY_NAME}" + TEMP_FILE="${INSTALL_DIR}/${BINARY_NAME}" + FINAL_FILE="${INSTALL_DIR}/safe-chain" + + info "Downloading from: $DOWNLOAD_URL" + download "$DOWNLOAD_URL" "$TEMP_FILE" + + # Rename and make executable + mv "$TEMP_FILE" "$FINAL_FILE" || error "Failed to move binary to $FINAL_FILE" + chmod +x "$FINAL_FILE" || error "Failed to make binary executable" + + info "Binary installed to: $FINAL_FILE" + + # Check if directory is in PATH + case ":$PATH:" in + *":$INSTALL_DIR:"*) + info "Installation directory is already in PATH" + ;; + *) + warn "Installation directory is not in PATH" + warn "Add the following line to your shell profile (~/.bashrc, ~/.zshrc, etc.):" + printf "\n export PATH=\"\$PATH:${INSTALL_DIR}\"\n\n" + ;; + esac + + # Execute safe-chain setup + info "Running safe-chain setup..." + if "$FINAL_FILE" setup; then + info "✓ safe-chain installed and configured successfully!" + else + warn "safe-chain was installed but setup encountered issues." + warn "You can run 'safe-chain setup' manually later." + fi + + info "Installation complete!" +} + +main From 8f80266ad3e8ed9d8b7c93b2e6d8e838fd12d946 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Mon, 1 Dec 2025 14:52:15 +0100 Subject: [PATCH 47/86] Update powershell scripts and installation scripts --- install-scripts/install-safe-chain.ps1 | 40 +------------------ install-scripts/install-safe-chain.sh | 14 +------ .../include-python/init-pwsh.ps1 | 5 ++- .../startup-scripts/init-pwsh.ps1 | 5 ++- 4 files changed, 10 insertions(+), 54 deletions(-) diff --git a/install-scripts/install-safe-chain.ps1 b/install-scripts/install-safe-chain.ps1 index ac85891..88c109a 100644 --- a/install-scripts/install-safe-chain.ps1 +++ b/install-scripts/install-safe-chain.ps1 @@ -1,15 +1,8 @@ # Downloads and installs safe-chain for Windows # Usage: iex (iwr "https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.ps1" -UseBasicParsing) -param( - [string]$Version -) - -# Configuration -if (-not $Version) { - $Version = if ($env:SAFE_CHAIN_VERSION) { $env:SAFE_CHAIN_VERSION } else { "v0.0.2-binaries-beta" } -} +$Version = "v0.0.3-binaries-beta" $InstallDir = Join-Path $env:USERPROFILE ".safe-chain\bin" $RepoUrl = "https://github.com/AikidoSec/safe-chain" @@ -91,37 +84,6 @@ function Install-SafeChain { Write-Info "Binary installed to: $finalFile" - # Check if directory is in PATH - $userPath = [Environment]::GetEnvironmentVariable("Path", "User") - if ($userPath -like "*$InstallDir*") { - Write-Info "Installation directory is already in PATH" - } - else { - Write-Warn "Installation directory is not in PATH" - Write-Host "" - Write-Warn "Would you like to add it to your PATH now? (Y/N)" - $response = Read-Host - - if ($response -eq "Y" -or $response -eq "y") { - try { - $newPath = "$userPath;$InstallDir" - [Environment]::SetEnvironmentVariable("Path", $newPath, "User") - Write-Info "Added to PATH. Please restart your terminal for changes to take effect." - } - catch { - Write-Warn "Failed to add to PATH automatically: $_" - Write-Warn "Please add the following directory to your PATH manually:" - Write-Host " $InstallDir" - } - } - else { - Write-Warn "Skipping PATH setup. Add the following directory to your PATH manually:" - Write-Host "" - Write-Host " $InstallDir" - Write-Host "" - } - } - # Execute safe-chain setup Write-Info "Running safe-chain setup..." diff --git a/install-scripts/install-safe-chain.sh b/install-scripts/install-safe-chain.sh index 37f3136..32d086b 100755 --- a/install-scripts/install-safe-chain.sh +++ b/install-scripts/install-safe-chain.sh @@ -7,7 +7,7 @@ set -e # Exit on error # Configuration -VERSION="${SAFE_CHAIN_VERSION:-v0.0.2-binaries-beta}" +VERSION="${SAFE_CHAIN_VERSION:-v0.0.3-binaries-beta}" INSTALL_DIR="${HOME}/.safe-chain/bin" REPO_URL="https://github.com/AikidoSec/safe-chain" @@ -99,18 +99,6 @@ main() { info "Binary installed to: $FINAL_FILE" - # Check if directory is in PATH - case ":$PATH:" in - *":$INSTALL_DIR:"*) - info "Installation directory is already in PATH" - ;; - *) - warn "Installation directory is not in PATH" - warn "Add the following line to your shell profile (~/.bashrc, ~/.zshrc, etc.):" - printf "\n export PATH=\"\$PATH:${INSTALL_DIR}\"\n\n" - ;; - esac - # Execute safe-chain setup info "Running safe-chain setup..." if "$FINAL_FILE" setup; then diff --git a/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-pwsh.ps1 b/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-pwsh.ps1 index 27a5065..50a6d0b 100644 --- a/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-pwsh.ps1 +++ b/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-pwsh.ps1 @@ -1,4 +1,7 @@ -$env:PATH = "$env:PATH;$HOME/.safe-chain/bin" +# Use cross-platform path separator (: on Unix, ; on Windows) +$pathSeparator = if ($IsWindows) { ';' } else { ':' } +$safeChainBin = Join-Path $HOME '.safe-chain' 'bin' +$env:PATH = "$env:PATH$pathSeparator$safeChainBin" function Write-SafeChainWarning { param([string]$Command) diff --git a/packages/safe-chain/src/shell-integration/startup-scripts/init-pwsh.ps1 b/packages/safe-chain/src/shell-integration/startup-scripts/init-pwsh.ps1 index 17ddeb2..ddf5aee 100644 --- a/packages/safe-chain/src/shell-integration/startup-scripts/init-pwsh.ps1 +++ b/packages/safe-chain/src/shell-integration/startup-scripts/init-pwsh.ps1 @@ -1,4 +1,7 @@ -$env:PATH = "$env:PATH;$HOME/.safe-chain/bin" +# Use cross-platform path separator (: on Unix, ; on Windows) +$pathSeparator = if ($IsWindows) { ';' } else { ':' } +$safeChainBin = Join-Path $HOME '.safe-chain' 'bin' +$env:PATH = "$env:PATH$pathSeparator$safeChainBin" function Write-SafeChainWarning { param([string]$Command) From b6ea61170fcb056968eafe5d52fa799797082b12 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Mon, 1 Dec 2025 14:59:20 +0100 Subject: [PATCH 48/86] Update release version --- install-scripts/install-safe-chain.ps1 | 2 +- install-scripts/install-safe-chain.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/install-scripts/install-safe-chain.ps1 b/install-scripts/install-safe-chain.ps1 index 88c109a..86c63db 100644 --- a/install-scripts/install-safe-chain.ps1 +++ b/install-scripts/install-safe-chain.ps1 @@ -2,7 +2,7 @@ # Usage: iex (iwr "https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.ps1" -UseBasicParsing) -$Version = "v0.0.3-binaries-beta" +$Version = "v0.0.4-binaries-beta" $InstallDir = Join-Path $env:USERPROFILE ".safe-chain\bin" $RepoUrl = "https://github.com/AikidoSec/safe-chain" diff --git a/install-scripts/install-safe-chain.sh b/install-scripts/install-safe-chain.sh index 32d086b..dcc7a3c 100755 --- a/install-scripts/install-safe-chain.sh +++ b/install-scripts/install-safe-chain.sh @@ -7,7 +7,7 @@ set -e # Exit on error # Configuration -VERSION="${SAFE_CHAIN_VERSION:-v0.0.3-binaries-beta}" +VERSION="${SAFE_CHAIN_VERSION:-v0.0.4-binaries-beta}" INSTALL_DIR="${HOME}/.safe-chain/bin" REPO_URL="https://github.com/AikidoSec/safe-chain" From 34c62c5268f0d947046f693d0f1c66e6c7ffbeb6 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Mon, 1 Dec 2025 15:28:10 +0100 Subject: [PATCH 49/86] Improve install script output --- install-scripts/install-safe-chain.ps1 | 9 +-------- install-scripts/install-safe-chain.sh | 7 +------ 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/install-scripts/install-safe-chain.ps1 b/install-scripts/install-safe-chain.ps1 index 86c63db..13d2f1a 100644 --- a/install-scripts/install-safe-chain.ps1 +++ b/install-scripts/install-safe-chain.ps1 @@ -85,16 +85,11 @@ function Install-SafeChain { Write-Info "Binary installed to: $finalFile" # Execute safe-chain setup - Write-Info "Running safe-chain setup..." - try { $env:Path = "$env:Path;$InstallDir" & $finalFile setup - if ($LASTEXITCODE -eq 0) { - Write-Info "✓ safe-chain installed and configured successfully!" - } - else { + if ($LASTEXITCODE -ne 0) { Write-Warn "safe-chain was installed but setup encountered issues." Write-Warn "You can run 'safe-chain setup' manually later." } @@ -103,8 +98,6 @@ function Install-SafeChain { Write-Warn "safe-chain was installed but setup encountered issues: $_" Write-Warn "You can run 'safe-chain setup' manually later." } - - Write-Info "Installation complete!" } # Run installation diff --git a/install-scripts/install-safe-chain.sh b/install-scripts/install-safe-chain.sh index dcc7a3c..cb899b6 100755 --- a/install-scripts/install-safe-chain.sh +++ b/install-scripts/install-safe-chain.sh @@ -100,15 +100,10 @@ main() { info "Binary installed to: $FINAL_FILE" # Execute safe-chain setup - info "Running safe-chain setup..." - if "$FINAL_FILE" setup; then - info "✓ safe-chain installed and configured successfully!" - else + if ! "$FINAL_FILE" setup; then warn "safe-chain was installed but setup encountered issues." warn "You can run 'safe-chain setup' manually later." fi - - info "Installation complete!" } main From 22b780ddcd0f8aee08fe926bae04ee1e88b3308b Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Mon, 1 Dec 2025 16:04:47 +0100 Subject: [PATCH 50/86] Remove npm-installed safe-chain --- install-scripts/install-safe-chain.ps1 | 27 ++++++++++++++++++++++++++ install-scripts/install-safe-chain.sh | 23 ++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/install-scripts/install-safe-chain.ps1 b/install-scripts/install-safe-chain.ps1 index 13d2f1a..e185d2a 100644 --- a/install-scripts/install-safe-chain.ps1 +++ b/install-scripts/install-safe-chain.ps1 @@ -36,10 +36,37 @@ function Get-Architecture { } } +# Check and uninstall npm global package if present +function Remove-NpmInstallation { + # Check if npm is available + if (-not (Get-Command npm -ErrorAction SilentlyContinue)) { + return + } + + # Check if safe-chain is installed as an npm global package + npm list -g @aikidosec/safe-chain 2>&1 | Out-Null + if ($LASTEXITCODE -eq 0) { + Write-Info "Detected npm global installation of @aikidosec/safe-chain" + Write-Info "Uninstalling npm version before installing binary version..." + + npm uninstall -g @aikidosec/safe-chain 2>&1 | Out-Null + if ($LASTEXITCODE -eq 0) { + Write-Info "Successfully uninstalled npm version" + } + else { + Write-Warn "Failed to uninstall npm version automatically" + Write-Warn "Please run: npm uninstall -g @aikidosec/safe-chain" + } + } +} + # Main installation function Install-SafeChain { Write-Info "Installing safe-chain $Version..." + # Check for existing npm installation + Remove-NpmInstallation + # Detect platform $arch = Get-Architecture $binaryName = "safe-chain-win-$arch.exe" diff --git a/install-scripts/install-safe-chain.sh b/install-scripts/install-safe-chain.sh index cb899b6..6f8480e 100755 --- a/install-scripts/install-safe-chain.sh +++ b/install-scripts/install-safe-chain.sh @@ -68,10 +68,33 @@ download() { fi } +# Check and uninstall npm global package if present +check_npm_installation() { + if ! command_exists npm; then + return + fi + + # Check if safe-chain is installed as an npm global package + if npm list -g @aikidosec/safe-chain >/dev/null 2>&1; then + info "Detected npm global installation of @aikidosec/safe-chain" + info "Uninstalling npm version before installing binary version..." + + if npm uninstall -g @aikidosec/safe-chain >/dev/null 2>&1; then + info "Successfully uninstalled npm version" + else + warn "Failed to uninstall npm version automatically" + warn "Please run: npm uninstall -g @aikidosec/safe-chain" + fi + fi +} + # Main installation main() { info "Installing safe-chain ${VERSION}..." + # Check for existing npm installation + check_npm_installation + # Detect platform OS=$(detect_os) ARCH=$(detect_arch) From eddb4f3f75f611175f5b17ae0da8f5758b3c55e0 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Tue, 2 Dec 2025 08:43:38 +0100 Subject: [PATCH 51/86] Check for volta installation --- install-scripts/install-safe-chain.ps1 | 28 ++++++++++++++++++++++++++ install-scripts/install-safe-chain.sh | 24 ++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/install-scripts/install-safe-chain.ps1 b/install-scripts/install-safe-chain.ps1 index e185d2a..9283170 100644 --- a/install-scripts/install-safe-chain.ps1 +++ b/install-scripts/install-safe-chain.ps1 @@ -60,6 +60,31 @@ function Remove-NpmInstallation { } } +# Check and uninstall Volta-managed package if present +function Remove-VoltaInstallation { + # Check if Volta is available + if (-not (Get-Command volta -ErrorAction SilentlyContinue)) { + return + } + + # Volta manages global packages in its own directory + # Check if safe-chain is installed via Volta + volta list @aikidosec/safe-chain 2>&1 | Out-Null + if ($LASTEXITCODE -eq 0) { + Write-Info "Detected Volta installation of @aikidosec/safe-chain" + Write-Info "Uninstalling Volta version before installing binary version..." + + volta uninstall @aikidosec/safe-chain 2>&1 | Out-Null + if ($LASTEXITCODE -eq 0) { + Write-Info "Successfully uninstalled Volta version" + } + else { + Write-Warn "Failed to uninstall Volta version automatically" + Write-Warn "Please run: volta uninstall @aikidosec/safe-chain" + } + } +} + # Main installation function Install-SafeChain { Write-Info "Installing safe-chain $Version..." @@ -67,6 +92,9 @@ function Install-SafeChain { # Check for existing npm installation Remove-NpmInstallation + # Check for existing Volta installation + Remove-VoltaInstallation + # Detect platform $arch = Get-Architecture $binaryName = "safe-chain-win-$arch.exe" diff --git a/install-scripts/install-safe-chain.sh b/install-scripts/install-safe-chain.sh index 6f8480e..671e52e 100755 --- a/install-scripts/install-safe-chain.sh +++ b/install-scripts/install-safe-chain.sh @@ -88,6 +88,27 @@ check_npm_installation() { fi } +# Check and uninstall Volta-managed package if present +check_volta_installation() { + if ! command_exists volta; then + return + fi + + # Volta manages global packages in its own directory + # Check if safe-chain is installed via Volta + if volta list @aikidosec/safe-chain >/dev/null 2>&1; then + info "Detected Volta installation of @aikidosec/safe-chain" + info "Uninstalling Volta version before installing binary version..." + + if volta uninstall @aikidosec/safe-chain >/dev/null 2>&1; then + info "Successfully uninstalled Volta version" + else + warn "Failed to uninstall Volta version automatically" + warn "Please run: volta uninstall @aikidosec/safe-chain" + fi + fi +} + # Main installation main() { info "Installing safe-chain ${VERSION}..." @@ -95,6 +116,9 @@ main() { # Check for existing npm installation check_npm_installation + # Check for existing Volta installation + check_volta_installation + # Detect platform OS=$(detect_os) ARCH=$(detect_arch) From b60cb63fdb45f9fda526f862a045f1b6d482ee53 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Tue, 2 Dec 2025 09:26:16 +0100 Subject: [PATCH 52/86] Add --include-python and --ci args --- install-scripts/install-safe-chain.ps1 | 38 ++++++++++++++-- install-scripts/install-safe-chain.sh | 63 ++++++++++++++++++++++++-- 2 files changed, 92 insertions(+), 9 deletions(-) diff --git a/install-scripts/install-safe-chain.ps1 b/install-scripts/install-safe-chain.ps1 index 9283170..b9a8cd8 100644 --- a/install-scripts/install-safe-chain.ps1 +++ b/install-scripts/install-safe-chain.ps1 @@ -1,6 +1,23 @@ # Downloads and installs safe-chain for Windows -# Usage: iex (iwr "https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.ps1" -UseBasicParsing) +# +# Usage examples: +# +# Default (JavaScript packages only): +# iex (iwr "https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.ps1" -UseBasicParsing) +# +# CI setup (JavaScript packages only): +# iex "& { $(iwr 'https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.ps1' -UseBasicParsing) } -ci" +# +# Include Python packages: +# iex "& { $(iwr 'https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.ps1' -UseBasicParsing) } -includepython" +# +# CI setup with Python packages: +# iex "& { $(iwr 'https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.ps1' -UseBasicParsing) } -ci -includepython" +param( + [switch]$ci, + [switch]$includepython +) $Version = "v0.0.4-binaries-beta" $InstallDir = Join-Path $env:USERPROFILE ".safe-chain\bin" @@ -139,19 +156,32 @@ function Install-SafeChain { Write-Info "Binary installed to: $finalFile" + # Build setup command based on parameters + $setupCmd = if ($ci) { "setup-ci" } else { "setup" } + $setupArgs = @() + if ($includepython) { + $setupArgs += "--include-python" + } + # Execute safe-chain setup + Write-Info "Running safe-chain $setupCmd $(if ($setupArgs) { $setupArgs -join ' ' })..." try { $env:Path = "$env:Path;$InstallDir" - & $finalFile setup + + if ($setupArgs) { + & $finalFile $setupCmd $setupArgs + } else { + & $finalFile $setupCmd + } if ($LASTEXITCODE -ne 0) { Write-Warn "safe-chain was installed but setup encountered issues." - Write-Warn "You can run 'safe-chain setup' manually later." + Write-Warn "You can run 'safe-chain $setupCmd $(if ($setupArgs) { $setupArgs -join ' ' })' manually later." } } catch { Write-Warn "safe-chain was installed but setup encountered issues: $_" - Write-Warn "You can run 'safe-chain setup' manually later." + Write-Warn "You can run 'safe-chain $setupCmd $(if ($setupArgs) { $setupArgs -join ' ' })' manually later." } } diff --git a/install-scripts/install-safe-chain.sh b/install-scripts/install-safe-chain.sh index 671e52e..f51cf1f 100755 --- a/install-scripts/install-safe-chain.sh +++ b/install-scripts/install-safe-chain.sh @@ -1,8 +1,24 @@ #!/bin/sh # Downloads and installs safe-chain, depending on the operating system and architecture -# Usage: curl -fsSL https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh -# or: wget -qO- https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh +# +# Usage examples: +# +# Default (JavaScript packages only): +# curl -fsSL https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh +# wget -qO- https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh +# +# CI setup (JavaScript packages only): +# curl -fsSL https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh -s -- --ci +# wget -qO- https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh -s -- --ci +# +# Include Python packages: +# curl -fsSL https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh -s -- --include-python +# wget -qO- https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh -s -- --include-python +# +# CI setup with Python packages: +# curl -fsSL https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh -s -- --ci --include-python +# wget -qO- https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh -s -- --ci --include-python set -e # Exit on error @@ -109,8 +125,32 @@ check_volta_installation() { fi } +# Parse command-line arguments +parse_arguments() { + for arg in "$@"; do + case "$arg" in + --ci) + USE_CI_SETUP=true + ;; + --include-python) + INCLUDE_PYTHON=true + ;; + *) + error "Unknown argument: $arg" + ;; + esac + done +} + # Main installation main() { + # Initialize argument flags + USE_CI_SETUP=false + INCLUDE_PYTHON=false + + # Parse command-line arguments + parse_arguments "$@" + info "Installing safe-chain ${VERSION}..." # Check for existing npm installation @@ -146,11 +186,24 @@ main() { info "Binary installed to: $FINAL_FILE" + # Build setup command based on arguments + SETUP_CMD="setup" + SETUP_ARGS="" + + if [ "$USE_CI_SETUP" = "true" ]; then + SETUP_CMD="setup-ci" + fi + + if [ "$INCLUDE_PYTHON" = "true" ]; then + SETUP_ARGS="--include-python" + fi + # Execute safe-chain setup - if ! "$FINAL_FILE" setup; then + info "Running safe-chain $SETUP_CMD $SETUP_ARGS..." + if ! "$FINAL_FILE" $SETUP_CMD $SETUP_ARGS; then warn "safe-chain was installed but setup encountered issues." - warn "You can run 'safe-chain setup' manually later." + warn "You can run 'safe-chain $SETUP_CMD $SETUP_ARGS' manually later." fi } -main +main "$@" From 2d87e1b8178ef12498659dabdc1f0de6f7ae9754 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Tue, 2 Dec 2025 09:49:14 +0100 Subject: [PATCH 53/86] Improve volta installation check --- install-scripts/install-safe-chain.ps1 | 5 +++-- install-scripts/install-safe-chain.sh | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/install-scripts/install-safe-chain.ps1 b/install-scripts/install-safe-chain.ps1 index b9a8cd8..1d2dab2 100644 --- a/install-scripts/install-safe-chain.ps1 +++ b/install-scripts/install-safe-chain.ps1 @@ -86,7 +86,7 @@ function Remove-VoltaInstallation { # Volta manages global packages in its own directory # Check if safe-chain is installed via Volta - volta list @aikidosec/safe-chain 2>&1 | Out-Null + volta list safe-chain 2>&1 | Out-Null if ($LASTEXITCODE -eq 0) { Write-Info "Detected Volta installation of @aikidosec/safe-chain" Write-Info "Uninstalling Volta version before installing binary version..." @@ -170,7 +170,8 @@ function Install-SafeChain { if ($setupArgs) { & $finalFile $setupCmd $setupArgs - } else { + } + else { & $finalFile $setupCmd } diff --git a/install-scripts/install-safe-chain.sh b/install-scripts/install-safe-chain.sh index f51cf1f..a65aee9 100755 --- a/install-scripts/install-safe-chain.sh +++ b/install-scripts/install-safe-chain.sh @@ -112,7 +112,7 @@ check_volta_installation() { # Volta manages global packages in its own directory # Check if safe-chain is installed via Volta - if volta list @aikidosec/safe-chain >/dev/null 2>&1; then + if volta list safe-chain >/dev/null 2>&1; then info "Detected Volta installation of @aikidosec/safe-chain" info "Uninstalling Volta version before installing binary version..." From c4a33ca1512bc8b68e34e51458656754bdd4271d Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Tue, 2 Dec 2025 10:30:59 +0100 Subject: [PATCH 54/86] Update readme.md --- README.md | 96 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 60 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 47f0894..de5be05 100644 --- a/README.md +++ b/README.md @@ -24,29 +24,43 @@ Aikido Safe Chain works on Node.js version 16 and above and supports the followi ## Installation -Installing the Aikido Safe Chain is easy. You just need 3 simple steps: +Installing the Aikido Safe Chain is easy with our one-line installer: -1. **Install the Aikido Safe Chain package globally** using npm: - ```shell - npm install -g @aikidosec/safe-chain - ``` -2. **Setup the shell integration** by running: +### Unix/Linux/macOS - ```shell - safe-chain setup - ``` +**Default installation (JavaScript packages only):** - To enable Python (pip/pip3/uv) support (beta), use the `--include-python` flag: +```shell +curl -fsSL https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh +``` - ```shell - safe-chain setup --include-python - ``` +**Include Python support (pip/pip3/uv):** -3. **❗Restart your terminal** to start using the Aikido Safe Chain. +```shell +curl -fsSL https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh -s -- --include-python +``` + +### Windows (PowerShell) + +**Default installation (JavaScript packages only):** + +```powershell +iex (iwr "https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.ps1" -UseBasicParsing) +``` + +**Include Python support (pip/pip3/uv):** + +```powershell +iex "& { $(iwr 'https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.ps1' -UseBasicParsing) } -includepython" +``` + +### Verify the installation + +1. **❗Restart your terminal** to start using the Aikido Safe Chain. - This step is crucial as it ensures that the shell aliases for npm, npx, yarn, pnpm, pnpx, bun, bunx, and pip/pip3 are loaded correctly. If you do not restart your terminal, the aliases will not be available. -4. **Verify the installation** by running one of the following commands: +2. **Verify the installation** by running one of the following commands: For JavaScript/Node.js: @@ -54,7 +68,7 @@ Installing the Aikido Safe Chain is easy. You just need 3 simple steps: npm install safe-chain-test ``` - For Python (beta): + For Python (if you enabled Python support): ```shell pip3 install safe-chain-pi-test @@ -165,21 +179,33 @@ You can protect your CI/CD pipelines from malicious packages by integrating Aiki For optimal protection in CI/CD environments, we recommend using **npm >= 10.4.0** as it provides full dependency tree scanning. Other package managers currently offer limited scanning of install command arguments only. -## Setup +## Installation for CI/CD -To use Aikido Safe Chain in CI/CD environments, run the following command after installing the package: +Use the `--ci` flag to automatically configure Aikido Safe Chain for CI/CD environments. This sets up executable shims in the PATH instead of shell aliases. +### Unix/Linux/macOS (GitHub Actions, Azure Pipelines, etc.) + +**JavaScript only:** ```shell -safe-chain setup-ci +curl -fsSL https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh -s -- --ci ``` -To enable Python (pip/pip3/uv) support (beta) in CI/CD, use the `--include-python` flag: - +**With Python support:** ```shell -safe-chain setup-ci --include-python +curl -fsSL https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh -s -- --ci --include-python ``` -This automatically configures your CI environment to use Aikido Safe Chain for all package manager commands. +### Windows (Azure Pipelines, etc.) + +**JavaScript only:** +```powershell +iex "& { $(iwr 'https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.ps1' -UseBasicParsing) } -ci" +``` + +**With Python support:** +```powershell +iex "& { $(iwr 'https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.ps1' -UseBasicParsing) } -ci -includepython" +``` ## Supported Platforms @@ -195,16 +221,15 @@ This automatically configures your CI environment to use Aikido Safe Chain for a node-version: "22" cache: "npm" -- name: Setup safe-chain - run: | - npm i -g @aikidosec/safe-chain - safe-chain setup-ci +- name: Install safe-chain + run: curl -fsSL https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh -s -- --ci --include-python - name: Install dependencies - run: | - npm ci + run: npm ci ``` +> **Note:** Remove `--include-python` if you don't need Python (pip/pip3/uv) support. + ## Azure DevOps Example ```yaml @@ -213,14 +238,13 @@ This automatically configures your CI environment to use Aikido Safe Chain for a versionSpec: "22.x" displayName: "Install Node.js" -- script: | - npm i -g @aikidosec/safe-chain - safe-chain setup-ci - displayName: "Install safe chain" +- script: curl -fsSL https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh -s -- --ci --include-python + displayName: "Install safe-chain" -- script: | - npm ci - displayName: "npm install and build" +- script: npm ci + displayName: "Install dependencies" ``` +> **Note:** Remove `--include-python` if you don't need Python (pip/pip3/uv) support. + After setup, all subsequent package manager commands in your CI pipeline will automatically be protected by Aikido Safe Chain's malware detection. From 9e1bdd4a31dc8b758d3ccc9b500276b93e0ea6b0 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Tue, 2 Dec 2025 11:57:23 +0100 Subject: [PATCH 55/86] Update docs: migration guide --- README.md | 8 ++- docs/npm-to-binary-migration.md | 89 +++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 docs/npm-to-binary-migration.md diff --git a/README.md b/README.md index de5be05..6e5470c 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,9 @@ Aikido Safe Chain works on Node.js version 16 and above and supports the followi ## Installation -Installing the Aikido Safe Chain is easy with our one-line installer: +Installing the Aikido Safe Chain is easy with our one-line installer. + +> ⚠️ **Already installed via npm?** See the [migration guide](docs/npm-to-binary-migration.md) to switch to the binary version. ### Unix/Linux/macOS @@ -186,11 +188,13 @@ Use the `--ci` flag to automatically configure Aikido Safe Chain for CI/CD envir ### Unix/Linux/macOS (GitHub Actions, Azure Pipelines, etc.) **JavaScript only:** + ```shell curl -fsSL https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh -s -- --ci ``` **With Python support:** + ```shell curl -fsSL https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh -s -- --ci --include-python ``` @@ -198,11 +202,13 @@ curl -fsSL https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-s ### Windows (Azure Pipelines, etc.) **JavaScript only:** + ```powershell iex "& { $(iwr 'https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.ps1' -UseBasicParsing) } -ci" ``` **With Python support:** + ```powershell iex "& { $(iwr 'https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.ps1' -UseBasicParsing) } -ci -includepython" ``` diff --git a/docs/npm-to-binary-migration.md b/docs/npm-to-binary-migration.md new file mode 100644 index 0000000..c0b8f9a --- /dev/null +++ b/docs/npm-to-binary-migration.md @@ -0,0 +1,89 @@ +# Migrating from npm global tool to binary installation + +If you previously installed safe-chain as an npm global package, you need to migrate to the binary installation. + +Depending on the version manager you're using, the uninstall process differs: + +### Standard npm (no version manager) + +1. **Clean up shell aliases:** + + ```bash + safe-chain teardown + ``` + +2. **Restart your terminal** + +3. **Uninstall the npm package:** + + ```bash + npm uninstall -g @aikidosec/safe-chain + ``` + +4. **Install the binary version** (see [Installation](../README.md#installation)) + +### nvm (Node Version Manager) + +**Important:** nvm installs global packages separately for each Node version, so safe-chain must be uninstalled from each version where it was installed. + +1. **Clean up shell aliases:** + + ```bash + safe-chain teardown + ``` + +2. **Restart your terminal** + +3. **Uninstall from all Node versions:** + + **Option A** - Automated script (recommended): + + ```bash + for version in $(nvm list | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+'); do nvm use $version && npm uninstall -g @aikidosec/safe-chain; done + ``` + + **Option B** - Manual per version: + + ```bash + nvm use + npm uninstall -g @aikidosec/safe-chain + ``` + + Repeat for each Node version where safe-chain was installed. + +4. **Install the binary version** (see [Installation](../README.md#installation)) + +### Volta + +1. **Clean up shell aliases:** + + ```bash + safe-chain teardown + ``` + +2. **Restart your terminal** + +3. **Uninstall the Volta package:** + + ```bash + volta uninstall @aikidosec/safe-chain + ``` + +4. **Install the binary version** (see [Installation](../README.md#installation)) + +## Troubleshooting + +### Shell aliases still present after migration + +1. Run `safe-chain teardown` (if the binary is installed) +2. Manually remove any safe-chain entries from your shell config files: + - Bash: `~/.bashrc` + - Zsh: `~/.zshrc` + - Fish: `~/.config/fish/config.fish` + - PowerShell: `$PROFILE` +3. Restart your terminal +4. Re-run the install script + +### "command not found: safe-chain" after migration + +The binary installation directory (`~/.safe-chain/bin`) may not be in your PATH. Restart your terminal. If the problem persists: re-run the installation of safe-chain. From 3002d272736dacac7705fe03480192a2067219a0 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Tue, 2 Dec 2025 13:58:27 +0100 Subject: [PATCH 56/86] Fix safe-chain in CI --- install-scripts/install-safe-chain.ps1 | 2 +- install-scripts/install-safe-chain.sh | 2 +- .../safe-chain/src/shell-integration/setup-ci.js | 13 ++++++++++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/install-scripts/install-safe-chain.ps1 b/install-scripts/install-safe-chain.ps1 index 1d2dab2..dcffe8a 100644 --- a/install-scripts/install-safe-chain.ps1 +++ b/install-scripts/install-safe-chain.ps1 @@ -19,7 +19,7 @@ param( [switch]$includepython ) -$Version = "v0.0.4-binaries-beta" +$Version = "v0.0.5-binaries-beta" $InstallDir = Join-Path $env:USERPROFILE ".safe-chain\bin" $RepoUrl = "https://github.com/AikidoSec/safe-chain" diff --git a/install-scripts/install-safe-chain.sh b/install-scripts/install-safe-chain.sh index a65aee9..fb7328d 100755 --- a/install-scripts/install-safe-chain.sh +++ b/install-scripts/install-safe-chain.sh @@ -23,7 +23,7 @@ set -e # Exit on error # Configuration -VERSION="${SAFE_CHAIN_VERSION:-v0.0.4-binaries-beta}" +VERSION="${SAFE_CHAIN_VERSION:-v0.0.5-binaries-beta}" INSTALL_DIR="${HOME}/.safe-chain/bin" REPO_URL="https://github.com/AikidoSec/safe-chain" diff --git a/packages/safe-chain/src/shell-integration/setup-ci.js b/packages/safe-chain/src/shell-integration/setup-ci.js index 9e0342d..28109fb 100644 --- a/packages/safe-chain/src/shell-integration/setup-ci.js +++ b/packages/safe-chain/src/shell-integration/setup-ci.js @@ -29,6 +29,7 @@ export async function setupCi() { ui.emptyLine(); const shimsDir = path.join(os.homedir(), ".safe-chain", "shims"); + const binDir = path.join(os.homedir(), ".safe-chain", "shims"); // Create the shims directory if it doesn't exist if (!fs.existsSync(shimsDir)) { fs.mkdirSync(shimsDir, { recursive: true }); @@ -36,7 +37,7 @@ export async function setupCi() { createShims(shimsDir); ui.writeInformation(`Created shims in ${shimsDir}`); - modifyPathForCi(shimsDir); + modifyPathForCi(shimsDir, binDir); ui.writeInformation(`Added shims directory to PATH for CI environments.`); } @@ -130,13 +131,18 @@ function createShims(shimsDir) { /** * @param {string} shimsDir + * @param {string} binDir * * @returns {void} */ -function modifyPathForCi(shimsDir) { +function modifyPathForCi(shimsDir, binDir) { if (process.env.GITHUB_PATH) { // In GitHub Actions, append the shims directory to GITHUB_PATH - fs.appendFileSync(process.env.GITHUB_PATH, shimsDir + os.EOL, "utf-8"); + fs.appendFileSync( + process.env.GITHUB_PATH, + shimsDir + os.EOL + binDir + os.EOL, + "utf-8" + ); ui.writeInformation( `Added shims directory to GITHUB_PATH for GitHub Actions.` ); @@ -147,6 +153,7 @@ function modifyPathForCi(shimsDir) { // ##vso[task.prependpath]/path/to/add // Logging this to stdout will cause the Azure Pipelines agent to pick it up ui.writeInformation("##vso[task.prependpath]" + shimsDir); + ui.writeInformation("##vso[task.prependpath]" + binDir); } } From f9b16cf03cef0927b43bb257e6066c78eccf410e Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Tue, 2 Dec 2025 14:19:53 +0100 Subject: [PATCH 57/86] Fix bins path for CI --- PR-TODOS.md | 9 +++++++++ packages/safe-chain/src/shell-integration/setup-ci.js | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 PR-TODOS.md diff --git a/PR-TODOS.md b/PR-TODOS.md new file mode 100644 index 0000000..dd23eef --- /dev/null +++ b/PR-TODOS.md @@ -0,0 +1,9 @@ +- [x] Update shims +- [x] Release pipeline +- [x] Install script +- [ ] Check if we can improve on python runner +- [x] Documentation +- [ ] Version in install scripts (to latest) +- [ ] Uncomment release pipeline (to latest) + +- [ ] Test with PATH shims (osx / windows) diff --git a/packages/safe-chain/src/shell-integration/setup-ci.js b/packages/safe-chain/src/shell-integration/setup-ci.js index 28109fb..9228673 100644 --- a/packages/safe-chain/src/shell-integration/setup-ci.js +++ b/packages/safe-chain/src/shell-integration/setup-ci.js @@ -29,7 +29,7 @@ export async function setupCi() { ui.emptyLine(); const shimsDir = path.join(os.homedir(), ".safe-chain", "shims"); - const binDir = path.join(os.homedir(), ".safe-chain", "shims"); + const binDir = path.join(os.homedir(), ".safe-chain", "bin"); // Create the shims directory if it doesn't exist if (!fs.existsSync(shimsDir)) { fs.mkdirSync(shimsDir, { recursive: true }); From 998d0c4faf5b06e9bbace361d2378dd4827fb7a8 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Tue, 2 Dec 2025 14:21:50 +0100 Subject: [PATCH 58/86] Update scripts --- install-scripts/install-safe-chain.ps1 | 2 +- install-scripts/install-safe-chain.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/install-scripts/install-safe-chain.ps1 b/install-scripts/install-safe-chain.ps1 index dcffe8a..84b8e23 100644 --- a/install-scripts/install-safe-chain.ps1 +++ b/install-scripts/install-safe-chain.ps1 @@ -19,7 +19,7 @@ param( [switch]$includepython ) -$Version = "v0.0.5-binaries-beta" +$Version = "v0.0.6-binaries-beta" $InstallDir = Join-Path $env:USERPROFILE ".safe-chain\bin" $RepoUrl = "https://github.com/AikidoSec/safe-chain" diff --git a/install-scripts/install-safe-chain.sh b/install-scripts/install-safe-chain.sh index fb7328d..1f85e1e 100755 --- a/install-scripts/install-safe-chain.sh +++ b/install-scripts/install-safe-chain.sh @@ -23,7 +23,7 @@ set -e # Exit on error # Configuration -VERSION="${SAFE_CHAIN_VERSION:-v0.0.5-binaries-beta}" +VERSION="${SAFE_CHAIN_VERSION:-v0.0.6-binaries-beta}" INSTALL_DIR="${HOME}/.safe-chain/bin" REPO_URL="https://github.com/AikidoSec/safe-chain" From b632e0acdaa67389d0ca8ed45df001dcb3a4b465 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Tue, 2 Dec 2025 15:00:51 +0100 Subject: [PATCH 59/86] Fix windows shim --- install-scripts/install-safe-chain.ps1 | 2 +- install-scripts/install-safe-chain.sh | 2 +- .../path-wrappers/templates/windows-wrapper.template.cmd | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/install-scripts/install-safe-chain.ps1 b/install-scripts/install-safe-chain.ps1 index 84b8e23..1bd3f0a 100644 --- a/install-scripts/install-safe-chain.ps1 +++ b/install-scripts/install-safe-chain.ps1 @@ -19,7 +19,7 @@ param( [switch]$includepython ) -$Version = "v0.0.6-binaries-beta" +$Version = "v0.0.7-binaries-beta" $InstallDir = Join-Path $env:USERPROFILE ".safe-chain\bin" $RepoUrl = "https://github.com/AikidoSec/safe-chain" diff --git a/install-scripts/install-safe-chain.sh b/install-scripts/install-safe-chain.sh index 1f85e1e..867f5b7 100755 --- a/install-scripts/install-safe-chain.sh +++ b/install-scripts/install-safe-chain.sh @@ -23,7 +23,7 @@ set -e # Exit on error # Configuration -VERSION="${SAFE_CHAIN_VERSION:-v0.0.6-binaries-beta}" +VERSION="${SAFE_CHAIN_VERSION:-v0.0.7-binaries-beta}" INSTALL_DIR="${HOME}/.safe-chain/bin" REPO_URL="https://github.com/AikidoSec/safe-chain" diff --git a/packages/safe-chain/src/shell-integration/path-wrappers/templates/windows-wrapper.template.cmd b/packages/safe-chain/src/shell-integration/path-wrappers/templates/windows-wrapper.template.cmd index d941a56..082d553 100644 --- a/packages/safe-chain/src/shell-integration/path-wrappers/templates/windows-wrapper.template.cmd +++ b/packages/safe-chain/src/shell-integration/path-wrappers/templates/windows-wrapper.template.cmd @@ -7,7 +7,7 @@ set "SHIM_DIR=%USERPROFILE%\.safe-chain\shims" call set "CLEAN_PATH=%%PATH:%SHIM_DIR%;=%%" REM Check if aikido command is available with clean PATH -set "PATH=%CLEAN_PATH%" & where {{AIKIDO_COMMAND}} >nul 2>&1 +set "PATH=%CLEAN_PATH%" & where safe-chain >nul 2>&1 if %errorlevel%==0 ( REM Call aikido command with clean PATH set "PATH=%CLEAN_PATH%" & safe-chain {{PACKAGE_MANAGER}} %* From ce1a2a6ca693a22a7d937b00c1a2976fcd5e9458 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Tue, 2 Dec 2025 15:17:58 +0100 Subject: [PATCH 60/86] Remove todo list --- PR-TODOS.md | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 PR-TODOS.md diff --git a/PR-TODOS.md b/PR-TODOS.md deleted file mode 100644 index dd23eef..0000000 --- a/PR-TODOS.md +++ /dev/null @@ -1,9 +0,0 @@ -- [x] Update shims -- [x] Release pipeline -- [x] Install script -- [ ] Check if we can improve on python runner -- [x] Documentation -- [ ] Version in install scripts (to latest) -- [ ] Uncomment release pipeline (to latest) - -- [ ] Test with PATH shims (osx / windows) From dc6f16a03455d21993de413426f3ff9af21e453d Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Tue, 2 Dec 2025 15:28:59 +0100 Subject: [PATCH 61/86] PR comments --- install-scripts/install-safe-chain.ps1 | 14 +------------- install-scripts/install-safe-chain.sh | 18 +----------------- packages/safe-chain/bin/safe-chain.js | 6 ++++++ 3 files changed, 8 insertions(+), 30 deletions(-) diff --git a/install-scripts/install-safe-chain.ps1 b/install-scripts/install-safe-chain.ps1 index 1bd3f0a..bc3aa23 100644 --- a/install-scripts/install-safe-chain.ps1 +++ b/install-scripts/install-safe-chain.ps1 @@ -1,18 +1,6 @@ # Downloads and installs safe-chain for Windows # -# Usage examples: -# -# Default (JavaScript packages only): -# iex (iwr "https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.ps1" -UseBasicParsing) -# -# CI setup (JavaScript packages only): -# iex "& { $(iwr 'https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.ps1' -UseBasicParsing) } -ci" -# -# Include Python packages: -# iex "& { $(iwr 'https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.ps1' -UseBasicParsing) } -includepython" -# -# CI setup with Python packages: -# iex "& { $(iwr 'https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.ps1' -UseBasicParsing) } -ci -includepython" +# Usage with "iex (iwr {url} -UseBasicParsing)" --> See README.md param( [switch]$ci, diff --git a/install-scripts/install-safe-chain.sh b/install-scripts/install-safe-chain.sh index 867f5b7..3fc5043 100755 --- a/install-scripts/install-safe-chain.sh +++ b/install-scripts/install-safe-chain.sh @@ -2,23 +2,7 @@ # Downloads and installs safe-chain, depending on the operating system and architecture # -# Usage examples: -# -# Default (JavaScript packages only): -# curl -fsSL https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh -# wget -qO- https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh -# -# CI setup (JavaScript packages only): -# curl -fsSL https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh -s -- --ci -# wget -qO- https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh -s -- --ci -# -# Include Python packages: -# curl -fsSL https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh -s -- --include-python -# wget -qO- https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh -s -- --include-python -# -# CI setup with Python packages: -# curl -fsSL https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh -s -- --ci --include-python -# wget -qO- https://raw.githubusercontent.com/AikidoSec/safe-chain/main/install-scripts/install-safe-chain.sh | sh -s -- --ci --include-python +# Usage with "curl -fsSL {url} | sh" --> See README.md set -e # Exit on error diff --git a/packages/safe-chain/bin/safe-chain.js b/packages/safe-chain/bin/safe-chain.js index 0a73f0e..f3b790b 100755 --- a/packages/safe-chain/bin/safe-chain.js +++ b/packages/safe-chain/bin/safe-chain.js @@ -141,6 +141,12 @@ async function getVersion() { * @param {import("../src/shell-integration/helpers.js").AikidoTool} tool */ async function executePip(tool) { + // Scanners for pip / pip3 / python / python3 use a slightly different approach: + // - They all use the same PIP_PACKAGE_MANAGER internally, but need some setup to be able to do so + // - It needs to set which tool to run (pip / pip3 / python / python3) + // - For python and python3, the -m pip/pip3 args are removed and later added again by the package manager + // - Python / python3 skips safe-chain if not being run with -m pip or -m pip3 + let args = process.argv.slice(3); setEcoSystem(tool.ecoSystem); initializePackageManager(PIP_PACKAGE_MANAGER); From a4f9f590a49bcccf3cff10271f68bb24fcc857c0 Mon Sep 17 00:00:00 2001 From: Reinier Criel Date: Tue, 2 Dec 2025 08:31:47 -0800 Subject: [PATCH 62/86] Don't modify config for config related commands --- .../src/packagemanager/pip/runPipCommand.js | 23 +++ .../packagemanager/pip/runPipCommand.spec.js | 97 +++++++++++ test/e2e/pip.e2e.spec.js | 153 ++++++++++++++++++ 3 files changed, 273 insertions(+) diff --git a/packages/safe-chain/src/packagemanager/pip/runPipCommand.js b/packages/safe-chain/src/packagemanager/pip/runPipCommand.js index 23485ff..37cfe76 100644 --- a/packages/safe-chain/src/packagemanager/pip/runPipCommand.js +++ b/packages/safe-chain/src/packagemanager/pip/runPipCommand.js @@ -46,6 +46,9 @@ function setFallbackCaBundleEnvironmentVariables(env, combinedCaPath) { * If the user has an existing PIP_CONFIG_FILE, a new temporary config is created that merges * their settings with safe-chain's, leaving the original file unchanged. * + * Special handling for 'pip config' commands: PIP_CONFIG_FILE is NOT overridden to allow + * users to read/write persistent config. Only CA environment variables are set for these commands. + * * @param {string} command - The pip command to execute (e.g., 'pip3') * @param {string[]} args - Command line arguments to pass to pip * @returns {Promise<{status: number}>} Exit status of the pip command @@ -59,6 +62,12 @@ export async function runPip(command, args) { // validates correctly under both MITM'd and tunneled HTTPS. const combinedCaPath = getCombinedCaBundlePath(); + // Commands that need access to persistent config/cache/state files + // These should not have PIP_CONFIG_FILE overridden as it would prevent them from + // reading/writing to the user's actual pip configuration and cache directories + const configRelatedCommands = ['config', 'cache', 'debug', 'completion']; + const isConfigRelatedCommand = args.length > 0 && configRelatedCommands.includes(args[0]); + // https://pip.pypa.io/en/stable/topics/https-certificates/ explains that the 'cert' param (which we're providing via INI file) // will tell pip to use the provided CA bundle for HTTPS verification. @@ -70,6 +79,20 @@ export async function runPip(command, args) { const pipConfigPath = path.join(tmpDir, `safe-chain-pip-${Date.now()}.ini`); let cleanupConfigPath = null; // Track temp file for cleanup + // For config-related commands, skip PIP_CONFIG_FILE override to allow persistent config/cache access + // Only set fallback CA environment variables which don't interfere with config operations + if (isConfigRelatedCommand) { + ui.writeVerbose(`Safe-chain: Skipping PIP_CONFIG_FILE override for 'pip ${args[0]}' command to allow persistent config/cache access.`); + setFallbackCaBundleEnvironmentVariables(env, combinedCaPath); + + const result = await safeSpawn(command, args, { + stdio: "inherit", + env, + }); + + return { status: result.status }; + } + // Note: Setting PIP_CONFIG_FILE overrides all pip config levels (Global/User/Site) per pip's loading order if (!env.PIP_CONFIG_FILE) { /** @type {{ global: { cert: string, proxy?: string } }} */ diff --git a/packages/safe-chain/src/packagemanager/pip/runPipCommand.spec.js b/packages/safe-chain/src/packagemanager/pip/runPipCommand.spec.js index d0df961..cf121f6 100644 --- a/packages/safe-chain/src/packagemanager/pip/runPipCommand.spec.js +++ b/packages/safe-chain/src/packagemanager/pip/runPipCommand.spec.js @@ -62,6 +62,103 @@ describe("runPipCommand environment variable handling", () => { mock.reset(); }); + it("should NOT set PIP_CONFIG_FILE for 'pip config' commands to allow persistent config access", async () => { + const res = await runPip("pip3", ["config", "set", "global.index-url", "https://test.pypi.org/simple"]); + assert.strictEqual(res.status, 0); + assert.ok(capturedArgs, "safeSpawn should have been called"); + + // PIP_CONFIG_FILE should NOT be set for config commands + assert.strictEqual( + capturedArgs.options.env.PIP_CONFIG_FILE, + undefined, + "PIP_CONFIG_FILE should NOT be set for pip config commands" + ); + + // But CA environment variables should still be set + assert.strictEqual( + capturedArgs.options.env.REQUESTS_CA_BUNDLE, + "/tmp/test-combined-ca.pem", + "REQUESTS_CA_BUNDLE should still be set" + ); + assert.strictEqual( + capturedArgs.options.env.SSL_CERT_FILE, + "/tmp/test-combined-ca.pem", + "SSL_CERT_FILE should still be set" + ); + assert.strictEqual( + capturedArgs.options.env.PIP_CERT, + "/tmp/test-combined-ca.pem", + "PIP_CERT should still be set" + ); + }); + + it("should NOT set PIP_CONFIG_FILE for 'pip config get' commands", async () => { + const res = await runPip("pip3", ["config", "get", "global.index-url"]); + assert.strictEqual(res.status, 0); + assert.ok(capturedArgs, "safeSpawn should have been called"); + + assert.strictEqual( + capturedArgs.options.env.PIP_CONFIG_FILE, + undefined, + "PIP_CONFIG_FILE should NOT be set for pip config get" + ); + }); + + it("should NOT set PIP_CONFIG_FILE for 'pip config list' commands", async () => { + const res = await runPip("pip3", ["config", "list"]); + assert.strictEqual(res.status, 0); + assert.ok(capturedArgs, "safeSpawn should have been called"); + + assert.strictEqual( + capturedArgs.options.env.PIP_CONFIG_FILE, + undefined, + "PIP_CONFIG_FILE should NOT be set for pip config list" + ); + }); + + it("should NOT set PIP_CONFIG_FILE for 'pip cache' commands", async () => { + const res = await runPip("pip3", ["cache", "dir"]); + assert.strictEqual(res.status, 0); + assert.ok(capturedArgs, "safeSpawn should have been called"); + + assert.strictEqual( + capturedArgs.options.env.PIP_CONFIG_FILE, + undefined, + "PIP_CONFIG_FILE should NOT be set for pip cache commands" + ); + + // CA env vars should still be set + assert.strictEqual( + capturedArgs.options.env.SSL_CERT_FILE, + "/tmp/test-combined-ca.pem", + "SSL_CERT_FILE should still be set" + ); + }); + + it("should NOT set PIP_CONFIG_FILE for 'pip debug' commands", async () => { + const res = await runPip("pip3", ["debug"]); + assert.strictEqual(res.status, 0); + assert.ok(capturedArgs, "safeSpawn should have been called"); + + assert.strictEqual( + capturedArgs.options.env.PIP_CONFIG_FILE, + undefined, + "PIP_CONFIG_FILE should NOT be set for pip debug" + ); + }); + + it("should NOT set PIP_CONFIG_FILE for 'pip completion' commands", async () => { + const res = await runPip("pip3", ["completion", "--bash"]); + assert.strictEqual(res.status, 0); + assert.ok(capturedArgs, "safeSpawn should have been called"); + + assert.strictEqual( + capturedArgs.options.env.PIP_CONFIG_FILE, + undefined, + "PIP_CONFIG_FILE should NOT be set for pip completion" + ); + }); + it("should set PIP_CERT env var and create config file", async () => { const res = await runPip("pip3", ["install", "requests"]); assert.strictEqual(res.status, 0); diff --git a/test/e2e/pip.e2e.spec.js b/test/e2e/pip.e2e.spec.js index 9a1adec..fa5260c 100644 --- a/test/e2e/pip.e2e.spec.js +++ b/test/e2e/pip.e2e.spec.js @@ -336,4 +336,157 @@ describe("E2E: pip coverage", () => { `Output did not include expected text. Output was:\n${result.output}` ); }); + + it(`pip3 config set should work and persist configuration`, async () => { + const shell = await container.openShell("zsh"); + + // Set a config value + const setResult = await shell.runCommand( + "pip3 config set global.timeout 60" + ); + + assert.ok( + setResult.output.includes("Writing to"), + `pip3 config set should write config. Output was:\n${setResult.output}` + ); + + // Verify it was persisted by reading it back + const getResult = await shell.runCommand( + "pip3 config get global.timeout" + ); + + assert.ok( + getResult.output.includes("60"), + `Config value should be 60. Output was:\n${getResult.output}` + ); + }); + + it(`pip3 config list should show user configuration`, async () => { + const shell = await container.openShell("zsh"); + + // Set a value first + await shell.runCommand("pip3 config set global.timeout 90"); + + // List config + const listResult = await shell.runCommand("pip3 config list"); + + assert.ok( + listResult.output.includes("timeout") && listResult.output.includes("90"), + `Config list should show timeout=90. Output was:\n${listResult.output}` + ); + }); + + it(`pip3 config unset should remove configuration`, async () => { + const shell = await container.openShell("zsh"); + + // Set a value + await shell.runCommand("pip3 config set global.timeout 120"); + + // Verify it exists + const getResult = await shell.runCommand("pip3 config get global.timeout"); + assert.ok(getResult.output.includes("120")); + + // Unset it + const unsetResult = await shell.runCommand("pip3 config unset global.timeout"); + assert.ok( + unsetResult.output.includes("Writing to"), + `pip3 config unset should write config. Output was:\n${unsetResult.output}` + ); + }); + + it(`pip3 cache dir should return cache directory path`, async () => { + const shell = await container.openShell("zsh"); + + const result = await shell.runCommand("pip3 cache dir"); + + // Should output a directory path + assert.ok( + result.output.includes("/") && result.output.includes("cache"), + `Should output a cache directory path. Output was:\n${result.output}` + ); + }); + + it(`pip3 cache info should show cache information`, async () => { + const shell = await container.openShell("zsh"); + + // Install something first to populate cache + await shell.runCommand("pip3 install --break-system-packages certifi"); + + const result = await shell.runCommand("pip3 cache info"); + + // Output should contain cache-related information + assert.ok( + result.output.match(/cache|wheel|http/i), + `Should output cache information. Output was:\n${result.output}` + ); + }); + + it(`pip3 cache list should list cached packages`, async () => { + const shell = await container.openShell("zsh"); + + // Download a package to ensure something is in cache + await shell.runCommand("pip3 download certifi"); + + const result = await shell.runCommand("pip3 cache list certifi"); + + // Should show either cached wheels or "No locally built wheels" + assert.ok( + result.output.includes("certifi") || result.output.includes("No locally built"), + `Should output cache list information. Output was:\n${result.output}` + ); + }); + + it(`pip3 debug should output debug information`, async () => { + const shell = await container.openShell("zsh"); + + const result = await shell.runCommand("pip3 debug"); + + // Should contain debug information about pip environment + assert.ok( + result.output.match(/pip version|sys\.version|sys\.executable/i), + `Should output debug information. Output was:\n${result.output}` + ); + + // Should NOT show safe-chain's temporary config file in the debug output + assert.ok( + !result.output.includes("safe-chain-pip-"), + `Debug output should not reference safe-chain temp config. Output was:\n${result.output}` + ); + }); + + it(`pip3 completion should generate shell completion script`, async () => { + const shell = await container.openShell("zsh"); + + const result = await shell.runCommand("pip3 completion --zsh"); + + // Should output shell completion code + assert.ok( + result.output.includes("compdef") || result.output.includes("_pip") || result.output.includes("pip completion"), + `Should output completion code. Output was:\n${result.output}` + ); + }); + + it(`pip3 install still works after config operations`, async () => { + const shell = await container.openShell("zsh"); + + // Perform config operations + await shell.runCommand("pip3 config set global.timeout 60"); + await shell.runCommand("pip3 cache dir"); + + // Now install should still work with malware protection + const result = await shell.runCommand( + "pip3 install --break-system-packages certifi" + ); + + assert.ok( + result.output.includes("Successfully installed") || + result.output.includes("Requirement already satisfied"), + `Install should succeed after config operations. Output was:\n${result.output}` + ); + + assert.ok( + result.output.includes("no malware found."), + `Should still scan for malware. Output was:\n${result.output}` + ); + }); }); From 795e7af23e1daffea58860c5470cc86d711c342f Mon Sep 17 00:00:00 2001 From: Reinier Criel Date: Tue, 2 Dec 2025 08:44:43 -0800 Subject: [PATCH 63/86] Clean up comments --- .../safe-chain/src/packagemanager/pip/runPipCommand.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/safe-chain/src/packagemanager/pip/runPipCommand.js b/packages/safe-chain/src/packagemanager/pip/runPipCommand.js index 37cfe76..f7050a5 100644 --- a/packages/safe-chain/src/packagemanager/pip/runPipCommand.js +++ b/packages/safe-chain/src/packagemanager/pip/runPipCommand.js @@ -46,7 +46,7 @@ function setFallbackCaBundleEnvironmentVariables(env, combinedCaPath) { * If the user has an existing PIP_CONFIG_FILE, a new temporary config is created that merges * their settings with safe-chain's, leaving the original file unchanged. * - * Special handling for 'pip config' commands: PIP_CONFIG_FILE is NOT overridden to allow + * Special handling for commands that modify config/cache/state: PIP_CONFIG_FILE is NOT overridden to allow * users to read/write persistent config. Only CA environment variables are set for these commands. * * @param {string} command - The pip command to execute (e.g., 'pip3') @@ -79,10 +79,12 @@ export async function runPip(command, args) { const pipConfigPath = path.join(tmpDir, `safe-chain-pip-${Date.now()}.ini`); let cleanupConfigPath = null; // Track temp file for cleanup - // For config-related commands, skip PIP_CONFIG_FILE override to allow persistent config/cache access - // Only set fallback CA environment variables which don't interfere with config operations if (isConfigRelatedCommand) { ui.writeVerbose(`Safe-chain: Skipping PIP_CONFIG_FILE override for 'pip ${args[0]}' command to allow persistent config/cache access.`); + + // Still set the fallback CA bundle environment variables to avoid edge cases where a + // plugin or extension triggers a network call during config introspection + // This can do no harm setFallbackCaBundleEnvironmentVariables(env, combinedCaPath); const result = await safeSpawn(command, args, { From 20e63a58be225379844495d64191c796cc592e7e Mon Sep 17 00:00:00 2001 From: Reinier Criel Date: Tue, 2 Dec 2025 09:45:04 -0800 Subject: [PATCH 64/86] Add a better e2e test to cover the issue --- test/e2e/pip.e2e.spec.js | 50 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/test/e2e/pip.e2e.spec.js b/test/e2e/pip.e2e.spec.js index fa5260c..26ebb78 100644 --- a/test/e2e/pip.e2e.spec.js +++ b/test/e2e/pip.e2e.spec.js @@ -489,4 +489,54 @@ describe("E2E: pip coverage", () => { `Should still scan for malware. Output was:\n${result.output}` ); }); + + it(`pip3 download works after configuring pip settings`, async () => { + const shell = await container.openShell("zsh"); + + // Configure pip with timeout and extra index URL + const configTimeout = await shell.runCommand("pip3 config set global.timeout 60"); + assert.ok( + configTimeout.output.includes("Writing to"), + `Config set should succeed. Output was:\n${configTimeout.output}` + ); + + const configIndex = await shell.runCommand( + "pip3 config set global.extra-index-url https://pypi.org/simple" + ); + assert.ok( + configIndex.output.includes("Writing to"), + `Config set should succeed. Output was:\n${configIndex.output}` + ); + + // Verify config persisted + const listConfig = await shell.runCommand("pip3 config list"); + assert.ok( + listConfig.output.includes("timeout") && listConfig.output.includes("60"), + `Config should show timeout=60. Output was:\n${listConfig.output}` + ); + assert.ok( + listConfig.output.includes("extra-index-url") && listConfig.output.includes("pypi.org"), + `Config should show extra-index-url. Output was:\n${listConfig.output}` + ); + + // Now download packages with the configured settings + const downloadResult = await shell.runCommand( + "pip3 download -d /tmp/packages requests certifi" + ); + + assert.ok( + downloadResult.output.includes("no malware found."), + `Should scan for malware. Output was:\n${downloadResult.output}` + ); + + // Verify downloads succeeded + assert.ok( + downloadResult.output.includes("Saved") || downloadResult.output.includes("requests"), + `Download should succeed with configured settings. Output was:\n${downloadResult.output}` + ); + assert.ok( + downloadResult.output.includes("certifi"), + `Should download certifi. Output was:\n${downloadResult.output}` + ); + }); }); From b7453c670066cb16895c1ff77d79df568a223122 Mon Sep 17 00:00:00 2001 From: Hans Ott Date: Tue, 2 Dec 2025 19:05:05 +0100 Subject: [PATCH 65/86] Add NPM version and downloads badges --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 47f0894..c1ff682 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,9 @@ # Aikido Safe Chain +[![NPM Version](https://img.shields.io/npm/v/%40aikidosec%2Fsafe-chain?style=flat-square)](https://www.npmjs.com/package/@aikidosec/safe-chain) +[![NPM Downloads](https://img.shields.io/npm/dw/%40aikidosec%2Fsafe-chain?style=flat-square)](https://www.npmjs.com/package/@aikidosec/safe-chain) + - ✅ **Block malware on developer laptops and CI/CD** - ✅ **Supports npm and PyPI** more package managers coming - ✅ **Blocks packages newer than 24 hours** without breaking your build From 31a14a3f1b1e1a06627cddd18abb24f051c9c601 Mon Sep 17 00:00:00 2001 From: bitterpanda Date: Wed, 3 Dec 2025 10:47:28 +0100 Subject: [PATCH 66/86] Update packages/safe-chain/src/shell-integration/startup-scripts/init-pwsh.ps1 --- .../src/shell-integration/startup-scripts/init-pwsh.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/safe-chain/src/shell-integration/startup-scripts/init-pwsh.ps1 b/packages/safe-chain/src/shell-integration/startup-scripts/init-pwsh.ps1 index ddf5aee..0b7f5ee 100644 --- a/packages/safe-chain/src/shell-integration/startup-scripts/init-pwsh.ps1 +++ b/packages/safe-chain/src/shell-integration/startup-scripts/init-pwsh.ps1 @@ -89,4 +89,4 @@ function npm { } Invoke-WrappedCommand "npm" $args -} \ No newline at end of file +} From 4139275b764d5bafce76436850f82fc0dac5ebff Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Wed, 3 Dec 2025 10:06:58 +0100 Subject: [PATCH 67/86] Handle PR comments --- build.js | 11 +- .../include-python/init-fish.fish | 62 +++++----- .../include-python/init-posix.sh | 44 ++++---- .../include-python/init-pwsh.ps1 | 106 +++++++++--------- .../startup-scripts/init-fish.fish | 62 +++++----- .../startup-scripts/init-posix.sh | 44 ++++---- .../startup-scripts/init-pwsh.ps1 | 70 ++++++------ 7 files changed, 204 insertions(+), 195 deletions(-) diff --git a/build.js b/build.js index 24230cd..235968b 100644 --- a/build.js +++ b/build.js @@ -11,12 +11,21 @@ if (!target) { process.exit(1); } -(async function () { +(async function main() { await clearOutputFolder(); + + // Esbuild creates a single safe-chain.cjs with all dependencies included await bundleSafeChain(); + + // Copy assets that need to be included in the binary + // - All shell scripts that are used to setup safe-chain + // - Certifi because it contains static root certs for Python + // - Package.json for its metadata (package name, version, ...) await copyShellScripts(); await copyCertifi(); await copyAndModifyPackageJson(); + + // Creates a single binary with safe-chain.cjs and the copied assets await buildSafeChainBinary(target); })(); diff --git a/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-fish.fish b/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-fish.fish index 81e28ef..4c881ba 100644 --- a/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-fish.fish +++ b/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-fish.fish @@ -1,36 +1,5 @@ set -gx PATH $PATH $HOME/.safe-chain/bin -function printSafeChainWarning - set original_cmd $argv[1] - - # Fish equivalent of ANSI color codes: yellow background, black text for "Warning:" - set_color -b yellow black - printf "Warning:" - set_color normal - printf " safe-chain is not available to protect you from installing malware. %s will run without it.\n" $original_cmd - - # Cyan text for the install command - printf "Install safe-chain by using " - set_color cyan - printf "npm install -g @aikidosec/safe-chain" - set_color normal - printf ".\n" -end - -function wrapSafeChainCommand - set original_cmd $argv[1] - set cmd_args $argv[2..-1] - - if type -q safe-chain - # If the safe-chain command is available, just run it with the provided arguments - safe-chain $original_cmd $cmd_args - else - # If the safe-chain command is not available, print a warning and run the original command - printSafeChainWarning $original_cmd - command $original_cmd $cmd_args - end -end - function npx wrapSafeChainCommand "npx" $argv end @@ -92,3 +61,34 @@ end function python3 wrapSafeChainCommand "python3" $argv end + +function printSafeChainWarning + set original_cmd $argv[1] + + # Fish equivalent of ANSI color codes: yellow background, black text for "Warning:" + set_color -b yellow black + printf "Warning:" + set_color normal + printf " safe-chain is not available to protect you from installing malware. %s will run without it.\n" $original_cmd + + # Cyan text for the install command + printf "Install safe-chain by using " + set_color cyan + printf "npm install -g @aikidosec/safe-chain" + set_color normal + printf ".\n" +end + +function wrapSafeChainCommand + set original_cmd $argv[1] + set cmd_args $argv[2..-1] + + if type -q safe-chain + # If the safe-chain command is available, just run it with the provided arguments + safe-chain $original_cmd $cmd_args + else + # If the safe-chain command is not available, print a warning and run the original command + printSafeChainWarning $original_cmd + command $original_cmd $cmd_args + end +end diff --git a/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-posix.sh b/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-posix.sh index fd844fc..af5b18e 100644 --- a/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-posix.sh +++ b/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-posix.sh @@ -1,27 +1,5 @@ export PATH="$PATH:$HOME/.safe-chain/bin" -function printSafeChainWarning() { - # \033[43;30m is used to set the background color to yellow and text color to black - # \033[0m is used to reset the text formatting - printf "\033[43;30mWarning:\033[0m safe-chain is not available to protect you from installing malware. %s will run without it.\n" "$1" - # \033[36m is used to set the text color to cyan - printf "Install safe-chain by using \033[36mnpm install -g @aikidosec/safe-chain\033[0m.\n" -} - -function wrapSafeChainCommand() { - local original_cmd="$1" - - if command -v safe-chain > /dev/null 2>&1; then - # If the aikido command is available, just run it with the provided arguments - safe-chain "$@" - else - # If the aikido command is not available, print a warning and run the original command - printSafeChainWarning "$original_cmd" - - command "$original_cmd" "$@" - fi -} - function npx() { wrapSafeChainCommand "npx" "$@" } @@ -79,3 +57,25 @@ function python() { function python3() { wrapSafeChainCommand "python3" "$@" } + +function printSafeChainWarning() { + # \033[43;30m is used to set the background color to yellow and text color to black + # \033[0m is used to reset the text formatting + printf "\033[43;30mWarning:\033[0m safe-chain is not available to protect you from installing malware. %s will run without it.\n" "$1" + # \033[36m is used to set the text color to cyan + printf "Install safe-chain by using \033[36mnpm install -g @aikidosec/safe-chain\033[0m.\n" +} + +function wrapSafeChainCommand() { + local original_cmd="$1" + + if command -v safe-chain > /dev/null 2>&1; then + # If the aikido command is available, just run it with the provided arguments + safe-chain "$@" + else + # If the aikido command is not available, print a warning and run the original command + printSafeChainWarning "$original_cmd" + + command "$original_cmd" "$@" + fi +} diff --git a/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-pwsh.ps1 b/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-pwsh.ps1 index 50a6d0b..2edc93b 100644 --- a/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-pwsh.ps1 +++ b/packages/safe-chain/src/shell-integration/startup-scripts/include-python/init-pwsh.ps1 @@ -3,59 +3,6 @@ $pathSeparator = if ($IsWindows) { ';' } else { ':' } $safeChainBin = Join-Path $HOME '.safe-chain' 'bin' $env:PATH = "$env:PATH$pathSeparator$safeChainBin" -function Write-SafeChainWarning { - param([string]$Command) - - # PowerShell equivalent of ANSI color codes: yellow background, black text for "Warning:" - Write-Host "Warning:" -BackgroundColor Yellow -ForegroundColor Black -NoNewline - Write-Host " safe-chain is not available to protect you from installing malware. $Command will run without it." - - # Cyan text for the install command - Write-Host "Install safe-chain by using " -NoNewline - Write-Host "npm install -g @aikidosec/safe-chain" -ForegroundColor Cyan -NoNewline - Write-Host "." -} - -function Test-CommandAvailable { - param([string]$Command) - - try { - Get-Command $Command -ErrorAction Stop | Out-Null - return $true - } - catch { - return $false - } -} - -function Invoke-RealCommand { - param( - [string]$Command, - [string[]]$Arguments - ) - - # Find the real executable to avoid calling our wrapped functions - $realCommand = Get-Command -Name $Command -CommandType Application | Select-Object -First 1 - if ($realCommand) { - & $realCommand.Source @Arguments - } -} - -function Invoke-WrappedCommand { - param( - [string]$OriginalCmd, - [string[]]$Arguments - ) - - if (Test-CommandAvailable "safe-chain") { - & safe-chain $OriginalCmd @Arguments - } - else { - Write-SafeChainWarning $OriginalCmd - Invoke-RealCommand $OriginalCmd $Arguments - } -} - function npx { Invoke-WrappedCommand "npx" $args } @@ -113,3 +60,56 @@ function python3 { Invoke-WrappedCommand 'python3' $args } + +function Write-SafeChainWarning { + param([string]$Command) + + # PowerShell equivalent of ANSI color codes: yellow background, black text for "Warning:" + Write-Host "Warning:" -BackgroundColor Yellow -ForegroundColor Black -NoNewline + Write-Host " safe-chain is not available to protect you from installing malware. $Command will run without it." + + # Cyan text for the install command + Write-Host "Install safe-chain by using " -NoNewline + Write-Host "npm install -g @aikidosec/safe-chain" -ForegroundColor Cyan -NoNewline + Write-Host "." +} + +function Test-CommandAvailable { + param([string]$Command) + + try { + Get-Command $Command -ErrorAction Stop | Out-Null + return $true + } + catch { + return $false + } +} + +function Invoke-RealCommand { + param( + [string]$Command, + [string[]]$Arguments + ) + + # Find the real executable to avoid calling our wrapped functions + $realCommand = Get-Command -Name $Command -CommandType Application | Select-Object -First 1 + if ($realCommand) { + & $realCommand.Source @Arguments + } +} + +function Invoke-WrappedCommand { + param( + [string]$OriginalCmd, + [string[]]$Arguments + ) + + if (Test-CommandAvailable "safe-chain") { + & safe-chain $OriginalCmd @Arguments + } + else { + Write-SafeChainWarning $OriginalCmd + Invoke-RealCommand $OriginalCmd $Arguments + } +} diff --git a/packages/safe-chain/src/shell-integration/startup-scripts/init-fish.fish b/packages/safe-chain/src/shell-integration/startup-scripts/init-fish.fish index f697da2..b18ff96 100644 --- a/packages/safe-chain/src/shell-integration/startup-scripts/init-fish.fish +++ b/packages/safe-chain/src/shell-integration/startup-scripts/init-fish.fish @@ -1,36 +1,5 @@ set -gx PATH $PATH $HOME/.safe-chain/bin -function printSafeChainWarning - set original_cmd $argv[1] - - # Fish equivalent of ANSI color codes: yellow background, black text for "Warning:" - set_color -b yellow black - printf "Warning:" - set_color normal - printf " safe-chain is not available to protect you from installing malware. %s will run without it.\n" $original_cmd - - # Cyan text for the install command - printf "Install safe-chain by using " - set_color cyan - printf "npm install -g @aikidosec/safe-chain" - set_color normal - printf ".\n" -end - -function wrapSafeChainCommand - set original_cmd $argv[1] - set cmd_args $argv[2..-1] - - if type -q safe-chain - # If the safe-chain command is available, just run it with the provided arguments - safe-chain $original_cmd $cmd_args - else - # If the safe-chain command is not available, print a warning and run the original command - printSafeChainWarning $original_cmd - command $original_cmd $cmd_args - end -end - function npx wrapSafeChainCommand "npx" $argv end @@ -69,3 +38,34 @@ function npm wrapSafeChainCommand "npm" $argv end + +function printSafeChainWarning + set original_cmd $argv[1] + + # Fish equivalent of ANSI color codes: yellow background, black text for "Warning:" + set_color -b yellow black + printf "Warning:" + set_color normal + printf " safe-chain is not available to protect you from installing malware. %s will run without it.\n" $original_cmd + + # Cyan text for the install command + printf "Install safe-chain by using " + set_color cyan + printf "npm install -g @aikidosec/safe-chain" + set_color normal + printf ".\n" +end + +function wrapSafeChainCommand + set original_cmd $argv[1] + set cmd_args $argv[2..-1] + + if type -q safe-chain + # If the safe-chain command is available, just run it with the provided arguments + safe-chain $original_cmd $cmd_args + else + # If the safe-chain command is not available, print a warning and run the original command + printSafeChainWarning $original_cmd + command $original_cmd $cmd_args + end +end diff --git a/packages/safe-chain/src/shell-integration/startup-scripts/init-posix.sh b/packages/safe-chain/src/shell-integration/startup-scripts/init-posix.sh index 6d426c5..5c32143 100644 --- a/packages/safe-chain/src/shell-integration/startup-scripts/init-posix.sh +++ b/packages/safe-chain/src/shell-integration/startup-scripts/init-posix.sh @@ -1,27 +1,5 @@ export PATH="$PATH:$HOME/.safe-chain/bin" -function printSafeChainWarning() { - # \033[43;30m is used to set the background color to yellow and text color to black - # \033[0m is used to reset the text formatting - printf "\033[43;30mWarning:\033[0m safe-chain is not available to protect you from installing malware. %s will run without it.\n" "$1" - # \033[36m is used to set the text color to cyan - printf "Install safe-chain by using \033[36mnpm install -g @aikidosec/safe-chain\033[0m.\n" -} - -function wrapSafeChainCommand() { - local original_cmd="$1" - - if command -v safe-chain > /dev/null 2>&1; then - # If the aikido command is available, just run it with the provided arguments - safe-chain "$@" - else - # If the aikido command is not available, print a warning and run the original command - printSafeChainWarning "$original_cmd" - - command "$original_cmd" "$@" - fi -} - function npx() { wrapSafeChainCommand "npx" "$@" } @@ -56,3 +34,25 @@ function npm() { wrapSafeChainCommand "npm" "$@" } + +function printSafeChainWarning() { + # \033[43;30m is used to set the background color to yellow and text color to black + # \033[0m is used to reset the text formatting + printf "\033[43;30mWarning:\033[0m safe-chain is not available to protect you from installing malware. %s will run without it.\n" "$1" + # \033[36m is used to set the text color to cyan + printf "Install safe-chain by using \033[36mnpm install -g @aikidosec/safe-chain\033[0m.\n" +} + +function wrapSafeChainCommand() { + local original_cmd="$1" + + if command -v safe-chain > /dev/null 2>&1; then + # If the aikido command is available, just run it with the provided arguments + safe-chain "$@" + else + # If the aikido command is not available, print a warning and run the original command + printSafeChainWarning "$original_cmd" + + command "$original_cmd" "$@" + fi +} diff --git a/packages/safe-chain/src/shell-integration/startup-scripts/init-pwsh.ps1 b/packages/safe-chain/src/shell-integration/startup-scripts/init-pwsh.ps1 index 0b7f5ee..4f58406 100644 --- a/packages/safe-chain/src/shell-integration/startup-scripts/init-pwsh.ps1 +++ b/packages/safe-chain/src/shell-integration/startup-scripts/init-pwsh.ps1 @@ -3,6 +3,41 @@ $pathSeparator = if ($IsWindows) { ';' } else { ':' } $safeChainBin = Join-Path $HOME '.safe-chain' 'bin' $env:PATH = "$env:PATH$pathSeparator$safeChainBin" +function npx { + Invoke-WrappedCommand "npx" $args +} + +function yarn { + Invoke-WrappedCommand "yarn" $args +} + +function pnpm { + Invoke-WrappedCommand "pnpm" $args +} + +function pnpx { + Invoke-WrappedCommand "pnpx" $args +} + +function bun { + Invoke-WrappedCommand "bun" $args +} + +function bunx { + Invoke-WrappedCommand "bunx" $args +} + +function npm { + # If args is just -v or --version and nothing else, just run the npm version command + # This is because nvm uses this to check the version of npm + if (($args.Length -eq 1) -and (($args[0] -eq "-v") -or ($args[0] -eq "--version"))) { + Invoke-RealCommand "npm" $args + return + } + + Invoke-WrappedCommand "npm" $args +} + function Write-SafeChainWarning { param([string]$Command) @@ -55,38 +90,3 @@ function Invoke-WrappedCommand { Invoke-RealCommand $OriginalCmd $Arguments } } - -function npx { - Invoke-WrappedCommand "npx" $args -} - -function yarn { - Invoke-WrappedCommand "yarn" $args -} - -function pnpm { - Invoke-WrappedCommand "pnpm" $args -} - -function pnpx { - Invoke-WrappedCommand "pnpx" $args -} - -function bun { - Invoke-WrappedCommand "bun" $args -} - -function bunx { - Invoke-WrappedCommand "bunx" $args -} - -function npm { - # If args is just -v or --version and nothing else, just run the npm version command - # This is because nvm uses this to check the version of npm - if (($args.Length -eq 1) -and (($args[0] -eq "-v") -or ($args[0] -eq "--version"))) { - Invoke-RealCommand "npm" $args - return - } - - Invoke-WrappedCommand "npm" $args -} From c0076091c26f6a823cb811b9d946aac944385588 Mon Sep 17 00:00:00 2001 From: bitterpanda Date: Wed, 3 Dec 2025 11:10:47 +0100 Subject: [PATCH 68/86] Update packages/safe-chain/bin/safe-chain.js --- packages/safe-chain/bin/safe-chain.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/safe-chain/bin/safe-chain.js b/packages/safe-chain/bin/safe-chain.js index f3b790b..2bd47e1 100755 --- a/packages/safe-chain/bin/safe-chain.js +++ b/packages/safe-chain/bin/safe-chain.js @@ -134,7 +134,7 @@ async function getVersion() { return json.version; } - return "1.0.0"; + return "0.0.0"; } /** From b366466e1181ef98165f761cba19c9f8eeac9440 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Wed, 3 Dec 2025 11:26:11 +0100 Subject: [PATCH 69/86] Modify install scripts --- install-scripts/install-safe-chain.ps1 | 17 ++++++++++++----- install-scripts/install-safe-chain.sh | 23 +++++++++++++++-------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/install-scripts/install-safe-chain.ps1 b/install-scripts/install-safe-chain.ps1 index bc3aa23..3400bfc 100644 --- a/install-scripts/install-safe-chain.ps1 +++ b/install-scripts/install-safe-chain.ps1 @@ -92,12 +92,19 @@ function Remove-VoltaInstallation { # Main installation function Install-SafeChain { - Write-Info "Installing safe-chain $Version..." + # Build installation message + $installMsg = "Installing safe-chain $Version" + if ($includepython) { + $installMsg += " with python" + } + if ($ci) { + $installMsg += " in ci" + } - # Check for existing npm installation + Write-Info $installMsg + + # Check for existing safe-chain installation through npm or volta Remove-NpmInstallation - - # Check for existing Volta installation Remove-VoltaInstallation # Detect platform @@ -120,7 +127,6 @@ function Install-SafeChain { # Download binary $downloadUrl = "$RepoUrl/releases/download/$Version/$binaryName" $tempFile = Join-Path $InstallDir $binaryName - $finalFile = Join-Path $InstallDir "safe-chain.exe" Write-Info "Downloading from: $downloadUrl" @@ -135,6 +141,7 @@ function Install-SafeChain { } # Rename to final location + $finalFile = Join-Path $InstallDir "safe-chain.exe" try { Move-Item -Path $tempFile -Destination $finalFile -Force } diff --git a/install-scripts/install-safe-chain.sh b/install-scripts/install-safe-chain.sh index 3fc5043..9b34e0c 100755 --- a/install-scripts/install-safe-chain.sh +++ b/install-scripts/install-safe-chain.sh @@ -69,7 +69,7 @@ download() { } # Check and uninstall npm global package if present -check_npm_installation() { +remove_npm_installation() { if ! command_exists npm; then return fi @@ -89,7 +89,7 @@ check_npm_installation() { } # Check and uninstall Volta-managed package if present -check_volta_installation() { +remove_volta_installation() { if ! command_exists volta; then return fi @@ -135,13 +135,20 @@ main() { # Parse command-line arguments parse_arguments "$@" - info "Installing safe-chain ${VERSION}..." + # Build installation message + INSTALL_MSG="Installing safe-chain ${VERSION}" + if [ "$INCLUDE_PYTHON" = "true" ]; then + INSTALL_MSG="${INSTALL_MSG} with python" + fi + if [ "$USE_CI_SETUP" = "true" ]; then + INSTALL_MSG="${INSTALL_MSG} in ci" + fi - # Check for existing npm installation - check_npm_installation + info "$INSTALL_MSG" - # Check for existing Volta installation - check_volta_installation + # Check for existing safe-chain installation through npm or volta + remove_npm_installation + remove_volta_installation # Detect platform OS=$(detect_os) @@ -159,12 +166,12 @@ main() { # Download binary DOWNLOAD_URL="${REPO_URL}/releases/download/${VERSION}/${BINARY_NAME}" TEMP_FILE="${INSTALL_DIR}/${BINARY_NAME}" - FINAL_FILE="${INSTALL_DIR}/safe-chain" info "Downloading from: $DOWNLOAD_URL" download "$DOWNLOAD_URL" "$TEMP_FILE" # Rename and make executable + FINAL_FILE="${INSTALL_DIR}/safe-chain" mv "$TEMP_FILE" "$FINAL_FILE" || error "Failed to move binary to $FINAL_FILE" chmod +x "$FINAL_FILE" || error "Failed to make binary executable" From aa441e74831dbd2575654c482f999db41438d499 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Wed, 3 Dec 2025 11:31:35 +0100 Subject: [PATCH 70/86] Add comments for esm vs cjs __dirname implementation --- packages/safe-chain/bin/safe-chain.js | 6 +++++- packages/safe-chain/src/shell-integration/setup-ci.js | 6 +++++- packages/safe-chain/src/shell-integration/setup.js | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/safe-chain/bin/safe-chain.js b/packages/safe-chain/bin/safe-chain.js index 2bd47e1..7a1d6ab 100755 --- a/packages/safe-chain/bin/safe-chain.js +++ b/packages/safe-chain/bin/safe-chain.js @@ -20,8 +20,12 @@ import { } from "../src/packagemanager/pip/pipSettings.js"; /** @type {string} */ +// This checks the current file's dirname in a way that's compatible with: +// - Modulejs (import.meta.url) +// - ES modules (__dirname) +// This is needed because safe-chain's npm package is built using ES modules, +// but building the binaries requires commonjs. let dirname; - if (import.meta.url) { const filename = fileURLToPath(import.meta.url); dirname = path.dirname(filename); diff --git a/packages/safe-chain/src/shell-integration/setup-ci.js b/packages/safe-chain/src/shell-integration/setup-ci.js index 9228673..bc5c5e6 100644 --- a/packages/safe-chain/src/shell-integration/setup-ci.js +++ b/packages/safe-chain/src/shell-integration/setup-ci.js @@ -9,8 +9,12 @@ import { includePython } from "../config/cliArguments.js"; import { ECOSYSTEM_PY } from "../config/settings.js"; /** @type {string} */ +// This checks the current file's dirname in a way that's compatible with: +// - Modulejs (import.meta.url) +// - ES modules (__dirname) +// This is needed because safe-chain's npm package is built using ES modules, +// but building the binaries requires commonjs. let dirname; - if (import.meta.url) { const filename = fileURLToPath(import.meta.url); dirname = path.dirname(filename); diff --git a/packages/safe-chain/src/shell-integration/setup.js b/packages/safe-chain/src/shell-integration/setup.js index 45a1fb8..d5c4be9 100644 --- a/packages/safe-chain/src/shell-integration/setup.js +++ b/packages/safe-chain/src/shell-integration/setup.js @@ -9,8 +9,12 @@ import { includePython } from "../config/cliArguments.js"; import { fileURLToPath } from "url"; /** @type {string} */ +// This checks the current file's dirname in a way that's compatible with: +// - Modulejs (import.meta.url) +// - ES modules (__dirname) +// This is needed because safe-chain's npm package is built using ES modules, +// but building the binaries requires commonjs. let dirname; - if (import.meta.url) { const filename = fileURLToPath(import.meta.url); dirname = path.dirname(filename); From 0fd54b159b61787797e89dd8fdf1e977786f69f4 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Wed, 3 Dec 2025 11:38:27 +0100 Subject: [PATCH 71/86] Lock down @yao-pkg/pkg dependency --- build.js | 12 +- package-lock.json | 1435 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 3 +- 3 files changed, 1441 insertions(+), 9 deletions(-) diff --git a/build.js b/build.js index 235968b..7ebc3c4 100644 --- a/build.js +++ b/build.js @@ -103,14 +103,10 @@ async function copyAndModifyPackageJson() { function buildSafeChainBinary(target) { return new Promise((resolve, reject) => { - const pkg = spawn( - "npx", - ["@yao-pkg/pkg", "./build/package.json", "-t", target], - { - stdio: "inherit", - shell: true, - } - ); + const pkg = spawn("./node_modules/.bin/pkg", ["./build/package.json", "-t", target], { + stdio: "inherit", + shell: true, + }); pkg.on("close", (code) => { if (code !== 0) { diff --git a/package-lock.json b/package-lock.json index 16f42c7..3fb6a1c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "test/e2e" ], "devDependencies": { + "@yao-pkg/pkg": "6.10.1", "esbuild": "^0.27.0", "oxlint": "^1.22.0" } @@ -24,6 +25,73 @@ "resolved": "test/e2e", "link": true }, + "node_modules/@babel/generator": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.0.tgz", @@ -487,6 +555,58 @@ "node": "20 || >=22" } }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.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/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@npmcli/agent": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-4.0.0.tgz", @@ -723,6 +843,82 @@ "@types/node": "*" } }, + "node_modules/@yao-pkg/pkg": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/@yao-pkg/pkg/-/pkg-6.10.1.tgz", + "integrity": "sha512-M/eqDg0Iir2nmyZ06Q9ospIPv1Yk7K1du5iLiaYrfMogQcI6bqf82A026MVYngyLH8jZsquZvjNAbvgbW4Uwkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/generator": "^7.23.0", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", + "@yao-pkg/pkg-fetch": "3.5.30", + "into-stream": "^6.0.0", + "minimist": "^1.2.6", + "multistream": "^4.1.0", + "picocolors": "^1.1.0", + "picomatch": "^4.0.2", + "prebuild-install": "^7.1.1", + "resolve": "^1.22.10", + "stream-meter": "^1.0.4", + "tar": "^7.4.3", + "tinyglobby": "^0.2.11", + "unzipper": "^0.12.3" + }, + "bin": { + "pkg": "lib-es5/bin.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@yao-pkg/pkg-fetch": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@yao-pkg/pkg-fetch/-/pkg-fetch-3.5.30.tgz", + "integrity": "sha512-OrXQlsR3vE/IvwXSk8R5ETYbcxAFtUPmLkeepbG+ArN82TvlIwcUJ65tEWxLG3Tl89VRbmOupuhkXfmuaO05+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.6", + "picocolors": "^1.1.0", + "progress": "^2.0.3", + "semver": "^7.3.5", + "tar-fs": "^3.1.1", + "yargs": "^16.2.0" + }, + "bin": { + "pkg-fetch": "lib-es5/bin.js" + } + }, + "node_modules/@yao-pkg/pkg-fetch/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/@yao-pkg/pkg-fetch/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/agent-base": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", @@ -732,12 +928,230 @@ "node": ">= 14" } }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, + "node_modules/b4a": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.3.tgz", + "integrity": "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, + "node_modules/bare-events": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", + "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "bare-abort-controller": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + } + } + }, + "node_modules/bare-fs": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.2.tgz", + "integrity": "sha512-veTnRzkb6aPHOvSKIOy60KzURfBdUflr5VReI+NSaPL6xf+XLdONQgZgpYvUuZLVQ8dCqxpBAudaOM1+KpAUxw==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4", + "bare-url": "^2.2.2", + "fast-fifo": "^1.3.2" + }, + "engines": { + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-os": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.2.tgz", + "integrity": "sha512-T+V1+1srU2qYNBmJCXZkUY5vQ0B4FSlL3QDROnKQYOqeiQR8UbjNHlPa+TIbM4cuidiN9GaTaOZgSEgsvPbh5A==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "engines": { + "bare": ">=1.14.0" + } + }, + "node_modules/bare-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", + "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-os": "^3.0.1" + } + }, + "node_modules/bare-stream": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.7.0.tgz", + "integrity": "sha512-oyXQNicV1y8nc2aKffH+BUHFRXmx6VrPzlnaEvMhram0nPBrKcEdcyBg5r08D0i8VxngHFAiVyn1QKXpSG0B8A==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "streamx": "^2.21.0" + }, + "peerDependencies": { + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, + "node_modules/bare-url": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.3.2.tgz", + "integrity": "sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-path": "^3.0.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/cacache": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/cacache/-/cacache-20.0.3.tgz", @@ -793,6 +1207,48 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -805,6 +1261,13 @@ "node": ">= 0.8" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, "node_modules/debug": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", @@ -822,6 +1285,32 @@ } } }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -831,6 +1320,16 @@ "node": ">=0.4.0" } }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -845,6 +1344,23 @@ "node": ">= 0.4" } }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, "node_modules/encoding": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", @@ -855,6 +1371,16 @@ "iconv-lite": "^0.6.2" } }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/err-code": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", @@ -948,6 +1474,61 @@ "@esbuild/win32-x64": "0.27.0" } }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.7.0" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true, + "license": "(MIT OR WTFPL)", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "node_modules/form-data": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", @@ -964,6 +1545,39 @@ "node": ">= 6" } }, + "node_modules/from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true, + "license": "MIT" + }, + "node_modules/fs-extra": { + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.2.tgz", + "integrity": "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, "node_modules/fs-minipass": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", @@ -985,6 +1599,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -1022,6 +1646,13 @@ "node": ">= 0.4" } }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "dev": true, + "license": "MIT" + }, "node_modules/glob": { "version": "13.0.0", "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.0.tgz", @@ -1051,6 +1682,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -1147,6 +1785,27 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -1156,6 +1815,13 @@ "node": ">=0.8.19" } }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, "node_modules/ini": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz", @@ -1165,6 +1831,23 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/into-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz", + "integrity": "sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "from2": "^2.3.0", + "p-is-promise": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ip-address": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", @@ -1174,6 +1857,65 @@ "node": ">= 12" } }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", @@ -1244,6 +1986,19 @@ "node": ">= 0.6" } }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "10.1.1", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", @@ -1259,6 +2014,16 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/minipass": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", @@ -1381,18 +2146,72 @@ "node": ">= 18" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true, + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/multistream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/multistream/-/multistream-4.1.0.tgz", + "integrity": "sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "once": "^1.4.0", + "readable-stream": "^3.6.0" + } + }, + "node_modules/multistream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/nan": { "version": "2.23.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.23.0.tgz", "integrity": "sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ==", "license": "MIT" }, + "node_modules/napi-build-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "dev": true, + "license": "MIT" + }, "node_modules/negotiator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", @@ -1402,6 +2221,40 @@ "node": ">= 0.6" } }, + "node_modules/node-abi": { + "version": "3.85.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.85.0.tgz", + "integrity": "sha512-zsFhmbkAzwhTft6nd3VxcG0cvJsT70rL+BIGHWVq5fi6MwGrHwzqKaxXE+Hl2GmnGItnDKPPkO5/LQqjVkIdFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-forge": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.2.tgz", @@ -1411,6 +2264,13 @@ "node": ">= 6.13.0" } }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, "node_modules/node-pty": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.0.0.tgz", @@ -1455,6 +2315,16 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/oxlint": { "version": "1.22.0", "resolved": "https://registry.npmjs.org/oxlint/-/oxlint-1.22.0.tgz", @@ -1489,6 +2359,16 @@ } } }, + "node_modules/p-is-promise": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", + "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/p-map": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", @@ -1501,6 +2381,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, "node_modules/path-scurry": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", @@ -1517,6 +2404,105 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prebuild-install": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prebuild-install/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true, + "license": "ISC" + }, + "node_modules/prebuild-install/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prebuild-install/node_modules/tar-fs": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", + "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/prebuild-install/node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/proc-log": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", @@ -1526,6 +2512,23 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/promise-retry": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", @@ -1539,6 +2542,87 @@ "node": ">=10" } }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", @@ -1548,6 +2632,13 @@ "node": ">= 4" } }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -1567,6 +2658,53 @@ "node": ">=10" } }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -1617,6 +2755,190 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/stream-meter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/stream-meter/-/stream-meter-1.0.4.tgz", + "integrity": "sha512-4sOEtrbgFotXwnEuzzsQBYEV1elAeFSO8rSGeTwabuX1RRn/kEq9JVH7I0MRBhKVRR0sJkr0M0QCH7yOLf9fhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.1.4" + } + }, + "node_modules/streamx": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.23.0.tgz", + "integrity": "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tar": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.2.tgz", + "integrity": "sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tar-fs": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.1.tgz", + "integrity": "sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^4.0.1", + "bare-path": "^3.0.0" + } + }, + "node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/text-decoder": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", + "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -1660,6 +2982,37 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unzipper": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.12.3.tgz", + "integrity": "sha512-PZ8hTS+AqcGxsaQntl3IRBw65QrBI6lxzqDEL7IAo/XCEqRTKGfOX56Vea5TH9SZczRVxuzk1re04z/YjuYCJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bluebird": "~3.7.2", + "duplexer2": "~0.1.4", + "fs-extra": "^11.2.0", + "graceful-fs": "^4.2.2", + "node-int64": "^0.4.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, "node_modules/validate-npm-package-name": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.0.tgz", @@ -1669,12 +3022,94 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "license": "ISC" }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "packages/safe-chain": { "name": "@aikidosec/safe-chain", "version": "1.0.0", diff --git a/package.json b/package.json index 8428fe4..2793f9c 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "license": "AGPL-3.0-or-later", "devDependencies": { "oxlint": "^1.22.0", - "esbuild": "^0.27.0" + "esbuild": "^0.27.0", + "@yao-pkg/pkg": "6.10.1" } } From a578ee72137e8049ed377034b1616aba8756d0e6 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Wed, 3 Dec 2025 11:42:22 +0100 Subject: [PATCH 72/86] Fix windows build --- build.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/build.js b/build.js index 7ebc3c4..4711ce6 100644 --- a/build.js +++ b/build.js @@ -1,6 +1,7 @@ import { build } from "esbuild"; import { mkdir, cp, rm, readFile, writeFile } from "node:fs/promises"; import { spawn } from "node:child_process"; +import { resolve } from "node:path"; const target = process.argv[2]; if (!target) { @@ -102,8 +103,13 @@ async function copyAndModifyPackageJson() { } function buildSafeChainBinary(target) { - return new Promise((resolve, reject) => { - const pkg = spawn("./node_modules/.bin/pkg", ["./build/package.json", "-t", target], { + return new Promise((promiseResolve, reject) => { + // Use .cmd on Windows, resolve to absolute path for cross-platform compatibility + const pkgBin = process.platform === "win32" + ? resolve("node_modules/.bin/pkg.cmd") + : resolve("node_modules/.bin/pkg"); + + const pkg = spawn(pkgBin, ["./build/package.json", "-t", target], { stdio: "inherit", shell: true, }); @@ -112,7 +118,7 @@ function buildSafeChainBinary(target) { if (code !== 0) { reject(new Error(`pkg process exited with code ${code}`)); } else { - resolve(); + promiseResolve(); } }); }); From ac6567ba598e9f12dc37fcbf5931b277c595e2e6 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Wed, 3 Dec 2025 11:58:33 +0100 Subject: [PATCH 73/86] Make scripts release-proof again --- .github/workflows/build-and-release.yml | 8 ++++---- install-scripts/install-safe-chain.ps1 | 26 +++++++++++++++++++++++- install-scripts/install-safe-chain.sh | 27 ++++++++++++++++++++++++- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml index 4464c02..95a6c91 100644 --- a/.github/workflows/build-and-release.yml +++ b/.github/workflows/build-and-release.yml @@ -63,10 +63,10 @@ jobs: cp LICENSE packages/safe-chain/ cp -r docs packages/safe-chain/ - # - name: Publish to npm - # run: | - # echo "Publishing version ${{ steps.get_version.outputs.tag }} to NPM" - # npm publish --workspace=packages/safe-chain --access public --provenance + - name: Publish to npm + run: | + echo "Publishing version ${{ steps.get_version.outputs.tag }} to NPM" + npm publish --workspace=packages/safe-chain --access public --provenance - name: Download all binary artifacts uses: actions/download-artifact@v4 diff --git a/install-scripts/install-safe-chain.ps1 b/install-scripts/install-safe-chain.ps1 index 3400bfc..230bb11 100644 --- a/install-scripts/install-safe-chain.ps1 +++ b/install-scripts/install-safe-chain.ps1 @@ -7,7 +7,7 @@ param( [switch]$includepython ) -$Version = "v0.0.7-binaries-beta" +$Version = $env:SAFE_CHAIN_VERSION # Will be fetched from latest release if not set $InstallDir = Join-Path $env:USERPROFILE ".safe-chain\bin" $RepoUrl = "https://github.com/AikidoSec/safe-chain" @@ -31,6 +31,25 @@ function Write-Error-Custom { exit 1 } +# Fetch latest release version tag from GitHub +function Get-LatestVersion { + Write-Info "Fetching latest release version..." + + try { + $response = Invoke-RestMethod -Uri "https://api.github.com/repos/AikidoSec/safe-chain/releases/latest" -UseBasicParsing + $latestVersion = $response.tag_name + + if ([string]::IsNullOrWhiteSpace($latestVersion)) { + Write-Error-Custom "Failed to fetch latest version from GitHub API. Please set SAFE_CHAIN_VERSION environment variable." + } + + return $latestVersion + } + catch { + Write-Error-Custom "Failed to fetch latest version from GitHub API: $($_.Exception.Message). Please set SAFE_CHAIN_VERSION environment variable." + } +} + # Detect architecture function Get-Architecture { $arch = $env:PROCESSOR_ARCHITECTURE @@ -92,6 +111,11 @@ function Remove-VoltaInstallation { # Main installation function Install-SafeChain { + # Fetch latest version if VERSION is not set + if ([string]::IsNullOrWhiteSpace($script:Version)) { + $script:Version = Get-LatestVersion + } + # Build installation message $installMsg = "Installing safe-chain $Version" if ($includepython) { diff --git a/install-scripts/install-safe-chain.sh b/install-scripts/install-safe-chain.sh index 9b34e0c..0fbbf34 100755 --- a/install-scripts/install-safe-chain.sh +++ b/install-scripts/install-safe-chain.sh @@ -7,7 +7,7 @@ set -e # Exit on error # Configuration -VERSION="${SAFE_CHAIN_VERSION:-v0.0.7-binaries-beta}" +VERSION="${SAFE_CHAIN_VERSION:-}" # Will be fetched from latest release if not set INSTALL_DIR="${HOME}/.safe-chain/bin" REPO_URL="https://github.com/AikidoSec/safe-chain" @@ -54,6 +54,26 @@ command_exists() { command -v "$1" >/dev/null 2>&1 } +# Fetch latest release version tag from GitHub +fetch_latest_version() { + info "Fetching latest release version..." + + # Try using GitHub API to get the latest release tag + if command_exists curl; then + latest_version=$(curl -fsSL "https://api.github.com/repos/AikidoSec/safe-chain/releases/latest" | grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/') + elif command_exists wget; then + latest_version=$(wget -qO- "https://api.github.com/repos/AikidoSec/safe-chain/releases/latest" | grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/') + else + error "Neither curl nor wget found. Please install one of them or set SAFE_CHAIN_VERSION environment variable." + fi + + if [ -z "$latest_version" ]; then + error "Failed to fetch latest version from GitHub API. Please set SAFE_CHAIN_VERSION environment variable." + fi + + echo "$latest_version" +} + # Download file download() { url="$1" @@ -135,6 +155,11 @@ main() { # Parse command-line arguments parse_arguments "$@" + # Fetch latest version if VERSION is not set + if [ -z "$VERSION" ]; then + VERSION=$(fetch_latest_version) + fi + # Build installation message INSTALL_MSG="Installing safe-chain ${VERSION}" if [ "$INCLUDE_PYTHON" = "true" ]; then From 019d70cc5228efbcb7896b114a613bde82b5a690 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Wed, 3 Dec 2025 12:02:19 +0100 Subject: [PATCH 74/86] Fix install scripts --- install-scripts/install-safe-chain.ps1 | 3 +-- install-scripts/install-safe-chain.sh | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/install-scripts/install-safe-chain.ps1 b/install-scripts/install-safe-chain.ps1 index 230bb11..c7a6df5 100644 --- a/install-scripts/install-safe-chain.ps1 +++ b/install-scripts/install-safe-chain.ps1 @@ -33,8 +33,6 @@ function Write-Error-Custom { # Fetch latest release version tag from GitHub function Get-LatestVersion { - Write-Info "Fetching latest release version..." - try { $response = Invoke-RestMethod -Uri "https://api.github.com/repos/AikidoSec/safe-chain/releases/latest" -UseBasicParsing $latestVersion = $response.tag_name @@ -113,6 +111,7 @@ function Remove-VoltaInstallation { function Install-SafeChain { # Fetch latest version if VERSION is not set if ([string]::IsNullOrWhiteSpace($script:Version)) { + Write-Info "Fetching latest release version..." $script:Version = Get-LatestVersion } diff --git a/install-scripts/install-safe-chain.sh b/install-scripts/install-safe-chain.sh index 0fbbf34..2afb583 100755 --- a/install-scripts/install-safe-chain.sh +++ b/install-scripts/install-safe-chain.sh @@ -56,8 +56,6 @@ command_exists() { # Fetch latest release version tag from GitHub fetch_latest_version() { - info "Fetching latest release version..." - # Try using GitHub API to get the latest release tag if command_exists curl; then latest_version=$(curl -fsSL "https://api.github.com/repos/AikidoSec/safe-chain/releases/latest" | grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/') @@ -157,6 +155,7 @@ main() { # Fetch latest version if VERSION is not set if [ -z "$VERSION" ]; then + info "Fetching latest release version..." VERSION=$(fetch_latest_version) fi From 2085aad0054a838f332b5cc59e9b8401520d6a4c Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Wed, 3 Dec 2025 13:24:04 +0100 Subject: [PATCH 75/86] Improve logs for MITM handler --- .../src/registryProxy/mitmRequestHandler.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/safe-chain/src/registryProxy/mitmRequestHandler.js b/packages/safe-chain/src/registryProxy/mitmRequestHandler.js index bfc6c3e..cf2af5b 100644 --- a/packages/safe-chain/src/registryProxy/mitmRequestHandler.js +++ b/packages/safe-chain/src/registryProxy/mitmRequestHandler.js @@ -117,14 +117,16 @@ function forwardRequest(req, hostname, res, requestHandler) { proxyReq.on("error", (err) => { ui.writeVerbose( - `Safe-chain: Error occurred while proxying request: ${err.message}` + `Safe-chain: Error occurred while proxying request to ${req.url} for ${hostname}: ${err.message}` ); res.writeHead(502); res.end("Bad Gateway"); }); req.on("error", (err) => { - ui.writeError(`Safe-chain: Error reading client request: ${err.message}`); + ui.writeError( + `Safe-chain: Error reading client request to ${req.url} for ${hostname}: ${err.message}` + ); proxyReq.destroy(); }); @@ -175,7 +177,7 @@ function createProxyRequest(hostname, req, res, requestHandler) { const proxyReq = https.request(options, (proxyRes) => { proxyRes.on("error", (err) => { ui.writeError( - `Safe-chain: Error reading upstream response: ${err.message}` + `Safe-chain: Error reading upstream response to ${req.url} for ${hostname}: ${err.message}` ); if (!res.headersSent) { res.writeHead(502); @@ -184,7 +186,9 @@ function createProxyRequest(hostname, req, res, requestHandler) { }); if (!proxyRes.statusCode) { - ui.writeError("Safe-chain: Proxy response missing status code"); + ui.writeError( + `Safe-chain: Proxy response missing status code to ${req.url} for ${hostname}` + ); res.writeHead(500); res.end("Internal Server Error"); return; From aba771e35594f8be170505fef2c1193804ab0bf9 Mon Sep 17 00:00:00 2001 From: bitterpanda Date: Wed, 3 Dec 2025 14:14:55 +0100 Subject: [PATCH 76/86] add --compress GZip option to build --- build.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build.js b/build.js index 4711ce6..870d9f8 100644 --- a/build.js +++ b/build.js @@ -109,7 +109,11 @@ function buildSafeChainBinary(target) { ? resolve("node_modules/.bin/pkg.cmd") : resolve("node_modules/.bin/pkg"); - const pkg = spawn(pkgBin, ["./build/package.json", "-t", target], { + let pkgArgs = ["./build/package.json", "-t", "target"]; + + pkgArgs += ["--compress", "GZip"]; + + const pkg = spawn(pkgBin, pkgArgs, { stdio: "inherit", shell: true, }); From 9bf88dfd142c919377e4fcc953c203305666cb32 Mon Sep 17 00:00:00 2001 From: bitterpanda Date: Wed, 3 Dec 2025 14:17:07 +0100 Subject: [PATCH 77/86] .gitignore: add .idea folder --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 7c44b34..920883f 100644 --- a/.gitignore +++ b/.gitignore @@ -148,3 +148,6 @@ Claude.md # Build files build/ dist/ + +# Jetbrains IDEs +.idea/** From bdddf8f37e3506a0492875be78b5ce2366236cf2 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Wed, 3 Dec 2025 15:27:12 +0100 Subject: [PATCH 78/86] Fix scoping in powershell script --- install-scripts/install-safe-chain.ps1 | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/install-scripts/install-safe-chain.ps1 b/install-scripts/install-safe-chain.ps1 index c7a6df5..081d232 100644 --- a/install-scripts/install-safe-chain.ps1 +++ b/install-scripts/install-safe-chain.ps1 @@ -110,9 +110,9 @@ function Remove-VoltaInstallation { # Main installation function Install-SafeChain { # Fetch latest version if VERSION is not set - if ([string]::IsNullOrWhiteSpace($script:Version)) { + if ([string]::IsNullOrWhiteSpace($Version)) { Write-Info "Fetching latest release version..." - $script:Version = Get-LatestVersion + $Version = Get-LatestVersion } # Build installation message @@ -166,6 +166,10 @@ function Install-SafeChain { # Rename to final location $finalFile = Join-Path $InstallDir "safe-chain.exe" try { + # Remove existing file if present (Move-Item -Force doesn't overwrite) + if (Test-Path $finalFile) { + Remove-Item -Path $finalFile -Force + } Move-Item -Path $tempFile -Destination $finalFile -Force } catch { From 9da3411cc1db1ba2b5a2d22be02b5acd74c76c9a Mon Sep 17 00:00:00 2001 From: bitterpanda Date: Wed, 3 Dec 2025 15:32:51 +0100 Subject: [PATCH 79/86] Add decent logging to build script --- build.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/build.js b/build.js index 4711ce6..ee3cbe3 100644 --- a/build.js +++ b/build.js @@ -13,10 +13,13 @@ if (!target) { } (async function main() { + const startBuildTime = performance.now(); await clearOutputFolder(); + console.log("- Cleared output folder ✅") // Esbuild creates a single safe-chain.cjs with all dependencies included await bundleSafeChain(); + console.log("- Bundled safe-chain into safe-chain.cjs (es-build) ✅") // Copy assets that need to be included in the binary // - All shell scripts that are used to setup safe-chain @@ -25,9 +28,15 @@ if (!target) { await copyShellScripts(); await copyCertifi(); await copyAndModifyPackageJson(); + console.log("- Copied auxiliary resources (shell, package.json,...) ✅") // Creates a single binary with safe-chain.cjs and the copied assets await buildSafeChainBinary(target); + console.log(`- Built safe-chain binary for ${target} (pkg) ✅`) + + + const endBuildTime = performance.now(); + console.log(`🏁 Finished build in ${((endBuildTime - startBuildTime)/1000).toFixed(2)}s`); })(); async function clearOutputFolder() { From 267a5ab423b34dcbacd38b81e9f6a18d7838b1cd Mon Sep 17 00:00:00 2001 From: bitterpanda Date: Wed, 3 Dec 2025 15:33:16 +0100 Subject: [PATCH 80/86] add spacing where necessry in build.js --- build.js | 1 + 1 file changed, 1 insertion(+) diff --git a/build.js b/build.js index ee3cbe3..bd046c3 100644 --- a/build.js +++ b/build.js @@ -14,6 +14,7 @@ if (!target) { (async function main() { const startBuildTime = performance.now(); + await clearOutputFolder(); console.log("- Cleared output folder ✅") From b64d84c252454fe82675bd0b9923f890ed57d3b5 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Wed, 3 Dec 2025 15:54:03 +0100 Subject: [PATCH 81/86] Hard-code links and remove outdated information from readme --- README.md | 10 ++++------ docs/npm-to-binary-migration.md | 6 +++--- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 4b001e4..6cbb445 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![Aikido Safe Chain](./docs/banner.svg) +![Aikido Safe Chain](https://raw.githubusercontent.com/AikidoSec/safe-chain/main/docs/banner.svg) # Aikido Safe Chain @@ -10,7 +10,7 @@ - ✅ **Blocks packages newer than 24 hours** without breaking your build - ✅ **Tokenless, free, no build data shared** -Aikido Safe Chain works on Node.js version 16 and above and supports the following package managers: +Aikido Safe Chain supports the following package managers: - 📦 **npm** - 📦 **npx** @@ -29,7 +29,7 @@ Aikido Safe Chain works on Node.js version 16 and above and supports the followi Installing the Aikido Safe Chain is easy with our one-line installer. -> ⚠️ **Already installed via npm?** See the [migration guide](docs/npm-to-binary-migration.md) to switch to the binary version. +> ⚠️ **Already installed via npm?** See the [migration guide](https://github.com/AikidoSec/safe-chain/blob/main/docs/npm-to-binary-migration.md) to switch to the binary version. ### Unix/Linux/macOS @@ -111,7 +111,7 @@ The Aikido Safe Chain integrates with your shell to provide a seamless experienc - ✅ **PowerShell** - ✅ **PowerShell Core** -More information about the shell integration can be found in the [shell integration documentation](docs/shell-integration.md). +More information about the shell integration can be found in the [shell integration documentation](https://github.com/AikidoSec/safe-chain/blob/main/docs/shell-integration.md). ## Uninstallation @@ -182,8 +182,6 @@ You can set the minimum package age through multiple sources (in order of priori You can protect your CI/CD pipelines from malicious packages by integrating Aikido Safe Chain into your build process. This ensures that any packages installed during your automated builds are checked for malware before installation. -For optimal protection in CI/CD environments, we recommend using **npm >= 10.4.0** as it provides full dependency tree scanning. Other package managers currently offer limited scanning of install command arguments only. - ## Installation for CI/CD Use the `--ci` flag to automatically configure Aikido Safe Chain for CI/CD environments. This sets up executable shims in the PATH instead of shell aliases. diff --git a/docs/npm-to-binary-migration.md b/docs/npm-to-binary-migration.md index c0b8f9a..c29a044 100644 --- a/docs/npm-to-binary-migration.md +++ b/docs/npm-to-binary-migration.md @@ -20,7 +20,7 @@ Depending on the version manager you're using, the uninstall process differs: npm uninstall -g @aikidosec/safe-chain ``` -4. **Install the binary version** (see [Installation](../README.md#installation)) +4. **Install the binary version** (see [Installation](https://github.com/AikidoSec/safe-chain/blob/main/README.md#installation)) ### nvm (Node Version Manager) @@ -51,7 +51,7 @@ Depending on the version manager you're using, the uninstall process differs: Repeat for each Node version where safe-chain was installed. -4. **Install the binary version** (see [Installation](../README.md#installation)) +4. **Install the binary version** (see [Installation](https://github.com/AikidoSec/safe-chain/blob/main/README.md#installation)) ### Volta @@ -69,7 +69,7 @@ Depending on the version manager you're using, the uninstall process differs: volta uninstall @aikidosec/safe-chain ``` -4. **Install the binary version** (see [Installation](../README.md#installation)) +4. **Install the binary version** (see [Installation](https://github.com/AikidoSec/safe-chain/blob/main/README.md#installation)) ## Troubleshooting From 0a4c6ed5db937a93310980dd7b9f850dabaa5f29 Mon Sep 17 00:00:00 2001 From: bitterpanda Date: Wed, 3 Dec 2025 16:10:44 +0100 Subject: [PATCH 82/86] fi pkgArgs build --- build.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/build.js b/build.js index 2531fb6..91a5215 100644 --- a/build.js +++ b/build.js @@ -119,10 +119,12 @@ function buildSafeChainBinary(target) { ? resolve("node_modules/.bin/pkg.cmd") : resolve("node_modules/.bin/pkg"); - let pkgArgs = ["./build/package.json", "-t", "target"]; + let pkgArgs = []; - pkgArgs += ["--compress", "GZip"]; + // using gzip compression to lower binary size (original is 50MB) + pkgArgs = pkgArgs.concat(["--compress", "GZip"]); + pkgArgs = pkgArgs.concat(["./build/package.json", "-t", target]); const pkg = spawn(pkgBin, pkgArgs, { stdio: "inherit", shell: true, From 7abbd4aee9c92b147bcce350e4b5173bad48928a Mon Sep 17 00:00:00 2001 From: bitterpanda Date: Wed, 3 Dec 2025 16:18:24 +0100 Subject: [PATCH 83/86] report total size at the end --- build.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/build.js b/build.js index 91a5215..0f3621d 100644 --- a/build.js +++ b/build.js @@ -1,5 +1,5 @@ import { build } from "esbuild"; -import { mkdir, cp, rm, readFile, writeFile } from "node:fs/promises"; +import { mkdir, cp, rm, readFile, writeFile, stat } from "node:fs/promises"; import { spawn } from "node:child_process"; import { resolve } from "node:path"; @@ -36,8 +36,9 @@ if (!target) { console.log(`- Built safe-chain binary for ${target} (pkg) ✅`) - const endBuildTime = performance.now(); - console.log(`🏁 Finished build in ${((endBuildTime - startBuildTime)/1000).toFixed(2)}s`); + const totalBuildTime = (performance.now() - startBuildTime)/1000; + const totalSizeInMb = (await stat("./dist/safe-chain")).size / (1024*1024); + console.log(`🏁 Finished build in ${totalBuildTime.toFixed(2)}s, total build size: ${totalSizeInMb.toFixed(2)}MB`); })(); async function clearOutputFolder() { From 3a1d9c25af293950e8d2012b63665bd333d9da37 Mon Sep 17 00:00:00 2001 From: bitterpanda Date: Wed, 3 Dec 2025 16:25:42 +0100 Subject: [PATCH 84/86] rm --compress for now --- build.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/build.js b/build.js index 0f3621d..9650b41 100644 --- a/build.js +++ b/build.js @@ -122,9 +122,6 @@ function buildSafeChainBinary(target) { let pkgArgs = []; - // using gzip compression to lower binary size (original is 50MB) - pkgArgs = pkgArgs.concat(["--compress", "GZip"]); - pkgArgs = pkgArgs.concat(["./build/package.json", "-t", target]); const pkg = spawn(pkgBin, pkgArgs, { stdio: "inherit", From 6fa648d6cabf2f82e23de83abf8e48037dfa28a0 Mon Sep 17 00:00:00 2001 From: bitterpanda Date: Wed, 3 Dec 2025 16:27:25 +0100 Subject: [PATCH 85/86] make compat with windows: sze reporting --- build.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.js b/build.js index 9650b41..43d1ffb 100644 --- a/build.js +++ b/build.js @@ -37,7 +37,7 @@ if (!target) { const totalBuildTime = (performance.now() - startBuildTime)/1000; - const totalSizeInMb = (await stat("./dist/safe-chain")).size / (1024*1024); + const totalSizeInMb = (await stat("./dist/safe-chain" + (process.platform === "win32" ? ".bin" : ""))).size / (1024*1024); console.log(`🏁 Finished build in ${totalBuildTime.toFixed(2)}s, total build size: ${totalSizeInMb.toFixed(2)}MB`); })(); From 75f87678198803addd3482113c1e3d5c600de29c Mon Sep 17 00:00:00 2001 From: bitterpanda Date: Wed, 3 Dec 2025 16:30:19 +0100 Subject: [PATCH 86/86] needs to be safe-chain.exe instead of safe-chain.cmd for size --- build.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.js b/build.js index 43d1ffb..81619f4 100644 --- a/build.js +++ b/build.js @@ -37,7 +37,7 @@ if (!target) { const totalBuildTime = (performance.now() - startBuildTime)/1000; - const totalSizeInMb = (await stat("./dist/safe-chain" + (process.platform === "win32" ? ".bin" : ""))).size / (1024*1024); + const totalSizeInMb = (await stat("./dist/safe-chain" + (process.platform === "win32" ? ".exe" : ""))).size / (1024*1024); console.log(`🏁 Finished build in ${totalBuildTime.toFixed(2)}s, total build size: ${totalSizeInMb.toFixed(2)}MB`); })();