From 92da8ac75f9ea1369fcacd1075d3a68435010274 Mon Sep 17 00:00:00 2001 From: nghaninn <43451336+nghaninn@users.noreply.github.com> Date: Mon, 28 Jul 2025 10:11:44 +0800 Subject: [PATCH 1/7] fix: upgrade packages --- package-lock.json | 73 ++++++++++++++++++++++++++--------------------- package.json | 10 +++---- 2 files changed, 45 insertions(+), 38 deletions(-) diff --git a/package-lock.json b/package-lock.json index acabfc36..33a3d485 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,11 +13,11 @@ "@snyk/protect": "^1.1196.0", "@tradetrust-tt/dnsprove": "^2.18.0", "@tradetrust-tt/document-store": "^4.1.1", - "@tradetrust-tt/token-registry": "^5.2.0", - "@tradetrust-tt/tradetrust": "^6.10.0", - "@tradetrust-tt/tradetrust-config": "^1.19.0", - "@tradetrust-tt/tt-verify": "^9.5.0", - "@trustvc/trustvc": "^1.7.0", + "@tradetrust-tt/token-registry": "^5.5.0", + "@tradetrust-tt/tradetrust": "^6.10.2", + "@tradetrust-tt/tradetrust-config": "^1.19.1", + "@tradetrust-tt/tt-verify": "^9.5.1", + "@trustvc/trustvc": "^1.7.2", "ajv": "^8.4.0", "ajv-formats": "^2.1.0", "chalk": "^4.1.2", @@ -7284,9 +7284,10 @@ "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==" }, "node_modules/@tradetrust-tt/token-registry": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@tradetrust-tt/token-registry/-/token-registry-5.4.0.tgz", - "integrity": "sha512-J5IKJWPxHZXKzvpZBWCW8VoGaX5OJn5po5C4Edu2IRKT4z2zSW9qvZ9oZgUri8rog8XDY82z2O3S4PiQMlcfbQ==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@tradetrust-tt/token-registry/-/token-registry-5.5.0.tgz", + "integrity": "sha512-oiNI3L/zPxXPHaMltSPxZFaXH/Ej9MMy5eaiKXLOSiCxYwcqd7qe/NfFlvO1sR3OLASEnRNZxnWLl9yPY5+wnw==", + "license": "Apache-2.0", "dependencies": { "ethers": "^6.13.4" } @@ -7305,20 +7306,23 @@ }, "node_modules/@tradetrust-tt/token-registry-v5": { "name": "@tradetrust-tt/token-registry", - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@tradetrust-tt/token-registry/-/token-registry-5.4.0.tgz", - "integrity": "sha512-J5IKJWPxHZXKzvpZBWCW8VoGaX5OJn5po5C4Edu2IRKT4z2zSW9qvZ9oZgUri8rog8XDY82z2O3S4PiQMlcfbQ==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@tradetrust-tt/token-registry/-/token-registry-5.5.0.tgz", + "integrity": "sha512-oiNI3L/zPxXPHaMltSPxZFaXH/Ej9MMy5eaiKXLOSiCxYwcqd7qe/NfFlvO1sR3OLASEnRNZxnWLl9yPY5+wnw==", + "license": "Apache-2.0", "dependencies": { "ethers": "^6.13.4" } }, "node_modules/@tradetrust-tt/tradetrust": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/@tradetrust-tt/tradetrust/-/tradetrust-6.10.1.tgz", - "integrity": "sha512-Vk5TOlRKFbZ0qMitcYDcUGU5Nu5E5POHNlBnv61lrPoMq0gseIBaprgF/gIRC0Q4LVQLjCPOi1ufW11bDSpILQ==", + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/@tradetrust-tt/tradetrust/-/tradetrust-6.10.2.tgz", + "integrity": "sha512-4zj4zlsrrQiUJQxvl4N8Pa4cLHtFtFIs0lMg6daP/gRJXIn1QWD0Kl4mQ5FsjuopeM7JOBX/xok22SmElEtT5w==", "hasInstallScript": true, + "license": "Apache-2.0", "dependencies": { "@govtechsg/jsonld": "^0.1.1", + "@trustvc/w3c-vc": "^1.2.17", "ajv": "^8.12.0", "ajv-formats": "^2.1.1", "cross-fetch": "^4.0.0", @@ -7337,9 +7341,9 @@ } }, "node_modules/@tradetrust-tt/tradetrust-config": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/@tradetrust-tt/tradetrust-config/-/tradetrust-config-1.19.0.tgz", - "integrity": "sha512-wEwl1Ol2gvV5OfSRA7w4iqpxsKaNBs8N1qW9HYPOnT0Unn7lDb6Sse4L/7hJ7dxhDqtCj1JLG0Xpp0DUJ/BOyQ==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/@tradetrust-tt/tradetrust-config/-/tradetrust-config-1.19.1.tgz", + "integrity": "sha512-F6ZMa/nGEuV1nPuMTSkDq5sHW/OvqiR1/Qw6mrV2oOwQ2r43OFvWF7CnvPO24hcb8AverJtjjQEMEbE8c3LXyg==", "dependencies": { "ajv": "^8.12.0", "ajv-formats": "^2.1.1", @@ -7352,11 +7356,12 @@ } }, "node_modules/@tradetrust-tt/tradetrust-utils": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tradetrust-tt/tradetrust-utils/-/tradetrust-utils-2.4.0.tgz", - "integrity": "sha512-rbcKCcK1/rYiXhBpVzGxt6uTLwaZtTJPc4WWlWogOUtQA5DjSOOxAzNXOOSNIXnsXpxnBIFevncyz3ScK7Ot0w==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@tradetrust-tt/tradetrust-utils/-/tradetrust-utils-2.4.1.tgz", + "integrity": "sha512-kjeWA0Qg1guEREz+LsjIUs+nvJfLuSaNKouZXsR/E9pgziZPOo94981GhXQYdhTZXQq3bEJ24/Is0IWenFjo6g==", + "license": "Apache-2.0", "dependencies": { - "@tradetrust-tt/tt-verify": "^9.5.0", + "@tradetrust-tt/tt-verify": "^9.5.1", "dotenv": "^16.4.5", "ethers": "^5.8.0", "node-fetch": "^2.7.0" @@ -7370,13 +7375,14 @@ "license": "MIT" }, "node_modules/@tradetrust-tt/tt-verify": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/@tradetrust-tt/tt-verify/-/tt-verify-9.5.0.tgz", - "integrity": "sha512-7r+P3QHtkVzINp+9eDcvVLK0VgmmfFv41ocSp8homN2iyTQC7Sp5fU/xqjRkxYVaCbTO/2uT9tfJQjWJsqQWXg==", + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/@tradetrust-tt/tt-verify/-/tt-verify-9.5.1.tgz", + "integrity": "sha512-aPJ1yzGJlpa92iS6qkbS6/+Gfje006uVchgpXkr8249/diHRf/L/Qm19W92kHz7ZiloSJG8QKKU6i/bE4pQzGg==", + "license": "Apache-2.0", "dependencies": { "@tradetrust-tt/dnsprove": "^2.18.0", "@tradetrust-tt/document-store": "^4.1.1", - "@tradetrust-tt/token-registry": "^5.4.0", + "@tradetrust-tt/token-registry": "^5.5.0", "@tradetrust-tt/tradetrust": "^6.10.1", "axios": "^1.7.2", "debug": "^4.3.1", @@ -7395,17 +7401,18 @@ } }, "node_modules/@trustvc/trustvc": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@trustvc/trustvc/-/trustvc-1.7.0.tgz", - "integrity": "sha512-1spJLKIYyOCU87DiB/Kbsc0OghB6/SZXca+OmaFllrKEHxyT6rAJY2ihKBALIz3vifXY3Q94XZyDzjRxg4q7DQ==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@trustvc/trustvc/-/trustvc-1.7.2.tgz", + "integrity": "sha512-aIqnDPxgaeW+mSW9cI906WZZ2WhzNUXRG1TEqDv+WPUE8qDRpu/GQ9Epr1DA6Vm9EYl8OBIudQMBQmNeSwzwlg==", + "license": "Apache-2.0", "dependencies": { - "@tradetrust-tt/dnsprove": "^2.17.0", + "@tradetrust-tt/dnsprove": "^2.18.0", "@tradetrust-tt/ethers-aws-kms-signer": "^2.1.4", "@tradetrust-tt/token-registry-v4": "npm:@tradetrust-tt/token-registry@^4.16.0", - "@tradetrust-tt/token-registry-v5": "npm:@tradetrust-tt/token-registry@^5.3.0", - "@tradetrust-tt/tradetrust": "^6.10.1", - "@tradetrust-tt/tradetrust-utils": "^2.3.2", - "@tradetrust-tt/tt-verify": "^9.4.0", + "@tradetrust-tt/token-registry-v5": "npm:@tradetrust-tt/token-registry@^5.5.0", + "@tradetrust-tt/tradetrust": "^6.10.2", + "@tradetrust-tt/tradetrust-utils": "^2.4.1", + "@tradetrust-tt/tt-verify": "^9.5.1", "@trustvc/w3c-context": "^1.2.13", "@trustvc/w3c-credential-status": "^1.2.13", "@trustvc/w3c-issuer": "^1.2.4", diff --git a/package.json b/package.json index ed68cb0c..ded89018 100644 --- a/package.json +++ b/package.json @@ -73,11 +73,11 @@ "@snyk/protect": "^1.1196.0", "@tradetrust-tt/dnsprove": "^2.18.0", "@tradetrust-tt/document-store": "^4.1.1", - "@tradetrust-tt/token-registry": "^5.2.0", - "@tradetrust-tt/tradetrust": "^6.10.0", - "@tradetrust-tt/tradetrust-config": "^1.19.0", - "@tradetrust-tt/tt-verify": "^9.5.0", - "@trustvc/trustvc": "^1.7.0", + "@tradetrust-tt/token-registry": "^5.5.0", + "@tradetrust-tt/tradetrust": "^6.10.2", + "@tradetrust-tt/tradetrust-config": "^1.19.1", + "@tradetrust-tt/tt-verify": "^9.5.1", + "@trustvc/trustvc": "^1.7.2", "ajv": "^8.4.0", "ajv-formats": "^2.1.0", "chalk": "^4.1.2", From 1148af665c9003b7c91ed725acab528a7c458d56 Mon Sep 17 00:00:00 2001 From: nghaninn <43451336+nghaninn@users.noreply.github.com> Date: Mon, 28 Jul 2025 10:14:20 +0800 Subject: [PATCH 2/7] fix: astron test case --- .../__test__/__snapshots__/get-astron.test.ts.snap | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/commands/dns/txt-record/__test__/__snapshots__/get-astron.test.ts.snap b/src/commands/dns/txt-record/__test__/__snapshots__/get-astron.test.ts.snap index 835aac75..95ee8703 100644 --- a/src/commands/dns/txt-record/__test__/__snapshots__/get-astron.test.ts.snap +++ b/src/commands/dns/txt-record/__test__/__snapshots__/get-astron.test.ts.snap @@ -9,6 +9,13 @@ exports[`get should return dns-txt 1`] = ` "netId": "1338", "type": "openatts", }, + { + "addr": "0x94FD21A026E29E0686583b8be71Cb28a8ca1A8d4", + "dnssec": false, + "net": "ethereum", + "netId": "1338", + "type": "openatts", + }, { "addr": "0xc98d993271a997384889dd39c14cec0c1e0206c2", "dnssec": false, From 260a64e4b91c231c1413640c39db084088562628 Mon Sep 17 00:00:00 2001 From: nghaninn <43451336+nghaninn@users.noreply.github.com> Date: Tue, 29 Jul 2025 11:09:10 +0800 Subject: [PATCH 3/7] fix: upgrade package and fix test error --- package-lock.json | 197 +++++++++++++++++++++++++-- package.json | 5 +- patches/security-context+4.0.0.patch | 30 ++++ 3 files changed, 218 insertions(+), 14 deletions(-) create mode 100644 patches/security-context+4.0.0.patch diff --git a/package-lock.json b/package-lock.json index 33a3d485..25dd08b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,7 @@ "": { "name": "@tradetrust-tt/tradetrust-cli", "version": "0.0.0-development", + "hasInstallScript": true, "license": "GPL-3.0", "dependencies": { "@govtechsg/oa-encryption": "^1.3.5", @@ -17,7 +18,7 @@ "@tradetrust-tt/tradetrust": "^6.10.2", "@tradetrust-tt/tradetrust-config": "^1.19.1", "@tradetrust-tt/tt-verify": "^9.5.1", - "@trustvc/trustvc": "^1.7.2", + "@trustvc/trustvc": "^1.7.4", "ajv": "^8.4.0", "ajv-formats": "^2.1.0", "chalk": "^4.1.2", @@ -64,6 +65,7 @@ "git-cz": "^4.7.6", "jest": "^29.7.0", "jest-watch-typeahead": "^2.2.2", + "patch-package": "^8.0.0", "pkg": "^5.8.1", "prettier": "^2.3.0", "proxyquire": "^2.1.3", @@ -7356,9 +7358,9 @@ } }, "node_modules/@tradetrust-tt/tradetrust-utils": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@tradetrust-tt/tradetrust-utils/-/tradetrust-utils-2.4.1.tgz", - "integrity": "sha512-kjeWA0Qg1guEREz+LsjIUs+nvJfLuSaNKouZXsR/E9pgziZPOo94981GhXQYdhTZXQq3bEJ24/Is0IWenFjo6g==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@tradetrust-tt/tradetrust-utils/-/tradetrust-utils-2.4.2.tgz", + "integrity": "sha512-RFCgCMQTadLhSF94syRKCxfHyn678RrUw4wkChL1tdZkcq/LM4dAnZuJOELUhsDlstoM6cVxiisEDGBSM3mB4g==", "license": "Apache-2.0", "dependencies": { "@tradetrust-tt/tt-verify": "^9.5.1", @@ -7401,9 +7403,9 @@ } }, "node_modules/@trustvc/trustvc": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@trustvc/trustvc/-/trustvc-1.7.2.tgz", - "integrity": "sha512-aIqnDPxgaeW+mSW9cI906WZZ2WhzNUXRG1TEqDv+WPUE8qDRpu/GQ9Epr1DA6Vm9EYl8OBIudQMBQmNeSwzwlg==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@trustvc/trustvc/-/trustvc-1.7.4.tgz", + "integrity": "sha512-hRyK7ryuUzWZceVEFEjvzbULImqLxZbmJhD7lXH97TKgFcEWSB6ro+MZu8rzYHNDoBgRCVEiu0041aVH/JVZmg==", "license": "Apache-2.0", "dependencies": { "@tradetrust-tt/dnsprove": "^2.18.0", @@ -7411,7 +7413,7 @@ "@tradetrust-tt/token-registry-v4": "npm:@tradetrust-tt/token-registry@^4.16.0", "@tradetrust-tt/token-registry-v5": "npm:@tradetrust-tt/token-registry@^5.5.0", "@tradetrust-tt/tradetrust": "^6.10.2", - "@tradetrust-tt/tradetrust-utils": "^2.4.1", + "@tradetrust-tt/tradetrust-utils": "^2.4.2", "@tradetrust-tt/tt-verify": "^9.5.1", "@trustvc/w3c-context": "^1.2.13", "@trustvc/w3c-credential-status": "^1.2.13", @@ -8122,6 +8124,13 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true, + "license": "BSD-2-Clause" + }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -11548,6 +11557,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/find-yarn-workspace-root": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", + "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "micromatch": "^4.0.2" + } + }, "node_modules/findup-sync": { "version": "4.0.0", "dev": true, @@ -12882,8 +12901,6 @@ "version": "2.2.1", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "bin": { "is-docker": "cli.js" }, @@ -13224,8 +13241,6 @@ "version": "2.2.0", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "is-docker": "^2.0.0" }, @@ -14542,11 +14557,38 @@ "version": "1.0.0", "license": "MIT" }, + "node_modules/json-stable-stringify": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.3.0.tgz", + "integrity": "sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "isarray": "^2.0.5", + "jsonify": "^0.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "dev": true, "license": "MIT" }, + "node_modules/json-stable-stringify/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, "node_modules/json-stringify-safe": { "version": "5.0.1", "license": "ISC" @@ -14577,6 +14619,16 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", + "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", + "dev": true, + "license": "Public Domain", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/jsonld": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/jsonld/-/jsonld-6.0.0.tgz", @@ -14720,6 +14772,16 @@ "node": ">=0.10.0" } }, + "node_modules/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.11" + } + }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -18572,6 +18634,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.4", "dev": true, @@ -18771,6 +18850,87 @@ "node": ">=0.10.0" } }, + "node_modules/patch-package": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-8.0.0.tgz", + "integrity": "sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@yarnpkg/lockfile": "^1.1.0", + "chalk": "^4.1.2", + "ci-info": "^3.7.0", + "cross-spawn": "^7.0.3", + "find-yarn-workspace-root": "^2.0.0", + "fs-extra": "^9.0.0", + "json-stable-stringify": "^1.0.2", + "klaw-sync": "^6.0.0", + "minimist": "^1.2.6", + "open": "^7.4.2", + "rimraf": "^2.6.3", + "semver": "^7.5.3", + "slash": "^2.0.0", + "tmp": "^0.0.33", + "yaml": "^2.2.2" + }, + "bin": { + "patch-package": "index.js" + }, + "engines": { + "node": ">=14", + "npm": ">5" + } + }, + "node_modules/patch-package/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/patch-package/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/patch-package/node_modules/slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/patch-package/node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/path-exists": { "version": "4.0.0", "dev": true, @@ -22520,6 +22680,19 @@ "version": "3.1.1", "license": "ISC" }, + "node_modules/yaml": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, "node_modules/yargs": { "version": "17.7.2", "license": "MIT", diff --git a/package.json b/package.json index ded89018..f8bf3027 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "benchmark:run": "./scripts/benchmark.sh", "benchmark:clean": "rm -rf ./benchmark", "benchmark:full": "npm run benchmark:make-certs && npm run benchmark:run && npm run benchmark:clean", - "prepare": "snyk-protect", + "prepare": "patch-package && snyk-protect", "benchmark": "ts-node performance-tests/wrap-performance-test.ts", "pkg": "npx pkg ./package.json --out-path dist/@tradetrust-tt", "release:dryrun": "semantic-release --dry-run --no-ci" @@ -58,6 +58,7 @@ "git-cz": "^4.7.6", "jest": "^29.7.0", "jest-watch-typeahead": "^2.2.2", + "patch-package": "^8.0.0", "pkg": "^5.8.1", "prettier": "^2.3.0", "proxyquire": "^2.1.3", @@ -77,7 +78,7 @@ "@tradetrust-tt/tradetrust": "^6.10.2", "@tradetrust-tt/tradetrust-config": "^1.19.1", "@tradetrust-tt/tt-verify": "^9.5.1", - "@trustvc/trustvc": "^1.7.2", + "@trustvc/trustvc": "^1.7.4", "ajv": "^8.4.0", "ajv-formats": "^2.1.0", "chalk": "^4.1.2", diff --git a/patches/security-context+4.0.0.patch b/patches/security-context+4.0.0.patch new file mode 100644 index 00000000..18dd2785 --- /dev/null +++ b/patches/security-context+4.0.0.patch @@ -0,0 +1,30 @@ +diff --git a/node_modules/security-context/js/index.js b/node_modules/security-context/js/index.js +index 16048c7..e5da421 100644 +--- a/node_modules/security-context/js/index.js ++++ b/node_modules/security-context/js/index.js +@@ -8,10 +8,19 @@ exports.constants = constants; + const contexts = exports.contexts = new Map(); + + function _read(_path) { +- return JSON.parse( +- fs.readFileSync( +- path.join(__dirname, _path), +- {encoding: 'utf8'})); ++ try { ++ const filePath = path.join(__dirname, _path); ++ if (!fs.existsSync(filePath)) { ++ console.error(`Security context file not found: ${filePath}`); ++ return {}; ++ } ++ const fileContent = fs.readFileSync(filePath, {encoding: 'utf8'}); ++ if (!fileContent || fileContent === 'undefined') { ++ return {}; ++ } ++ return JSON.parse(fileContent); ++ } catch (error) { ++ console.error(`Error parsing security context file: ${_path}`, error); ++ return {}; ++ } + } + + contexts.set( From 5315c274e97ac4d308c172c688af035c5d2c831e Mon Sep 17 00:00:00 2001 From: nghaninn <43451336+nghaninn@users.noreply.github.com> Date: Tue, 29 Jul 2025 11:15:07 +0800 Subject: [PATCH 4/7] feat: add additional option to provide custom rpcUrl --- README.md | 21 +++ src/commands/shared.ts | 17 ++- .../document-store/document-store.test.ts | 117 ++++++++++++++- .../utils/__tests__/wallet.test.ts | 137 ++++++++++++++++++ src/implementations/utils/wallet.ts | 13 +- 5 files changed, 299 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d3b7d931..fddab214 100644 --- a/README.md +++ b/README.md @@ -592,6 +592,27 @@ rm ./examples/sample-key tradetrust deploy document-store "My Name" --network sepolia --key 0000000000000000000000000000000000000000000000000000000000000003 ``` +### Providing custom RPC URLs + +When interacting with the blockchain, you may want to connect to a different Ethereum provider than the default ones. All functions that interact with the blockchain support the `--rpc-url` option to specify a custom RPC endpoint: + +1. Using `--rpc-url` option where you provide the URL of your custom Ethereum RPC provider. +2. When `--rpc-url` is provided, it takes precedence over the default network provider. +3. This is useful for connecting to private networks, custom providers, or alternative public endpoints. + +Example: + +```bash +# Using custom RPC URL with document store deployment +tradetrust deploy document-store "My Name" --network sepolia --rpc-url https://custom-rpc.example.com + +# Using custom RPC URL with token registry operations +tradetrust deploy token-registry "My Registry" --network sepolia --rpc-url https://my-provider.com + +# Using custom RPC URL with document store operations +tradetrust document-store issue --address 0x1234... --hash 0xabcd... --network sepolia --rpc-url https://custom-endpoint.io +``` + ### Providing the Remarks and Encryption Key Enables users to attach encrypted remarks (up to 120 characters) to blockchain transactions. The encrypted remarks are stored immutably on the blockchain and can be viewed in the endorsement chain. This ensures secure and meaningful metadata is recorded alongside transactions. diff --git a/src/commands/shared.ts b/src/commands/shared.ts index 04149abb..954e3649 100644 --- a/src/commands/shared.ts +++ b/src/commands/shared.ts @@ -42,6 +42,15 @@ export const isWalletOption = (option: any): option is WalletOption => { return typeof option?.encryptedWalletPath === "string"; }; +export type RpcUrlOption = { + rpcUrl: string; +}; + +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types +export const isRpcUrlOption = (option: any): option is RpcUrlOption => { + return typeof option?.rpcUrl === "string"; +}; + export type WalletOrSignerOption = Partial | Partial | Partial; export interface GasPriceScale { @@ -121,5 +130,11 @@ export const withAwsKmsSignerOption = (yargs: Argv): Argv => "AWS KMS key id. Example: arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", }); +export const withRpcUrlOption = (yargs: Argv): Argv => + yargs.option("rpc-url", { + type: "string", + description: "Custom RPC URL to connect to. Example: https://mainnet.infura.io/v3/YOUR-PROJECT-ID", + }); + export const withNetworkAndWalletSignerOption = (yargs: Argv): Argv => - withNetworkOption(withAwsKmsSignerOption(withWalletOption(withPrivateKeyOption(yargs)))); + withNetworkOption(withRpcUrlOption(withAwsKmsSignerOption(withWalletOption(withPrivateKeyOption(yargs))))); diff --git a/src/implementations/deploy/document-store/document-store.test.ts b/src/implementations/deploy/document-store/document-store.test.ts index 20a04975..99eaa37d 100644 --- a/src/implementations/deploy/document-store/document-store.test.ts +++ b/src/implementations/deploy/document-store/document-store.test.ts @@ -1,6 +1,6 @@ import { deployDocumentStore } from "./document-store"; import { join } from "path"; -import { Wallet } from "ethers"; +import { Wallet, utils } from "ethers"; import { DocumentStoreFactory } from "@tradetrust-tt/document-store"; import { DeployDocumentStoreCommand } from "../../../commands/deploy/deploy.types"; @@ -104,5 +104,120 @@ describe("document-store", () => { const addr = await passedSigner.getAddress(); expect(mockedDeploy.mock.calls[0][1]).toStrictEqual(addr); }); + + describe("should use custom RPC URL", () => { + const createMockProvider = (chainId: number, name: string): any => ({ + getNetwork: jest.fn().mockResolvedValue({ chainId, name }), + getBalance: jest.fn(), + getTransactionCount: jest.fn(), + getGasPrice: jest.fn(), + getFeeData: jest.fn().mockResolvedValue({ + maxFeePerGas: utils.parseUnits("20", "gwei"), + maxPriorityFeePerGas: utils.parseUnits("2", "gwei"), + gasPrice: utils.parseUnits("20", "gwei"), + }), + estimateGas: jest.fn(), + call: jest.fn(), + sendTransaction: jest.fn(), + getBlock: jest.fn(), + getTransaction: jest.fn(), + getTransactionReceipt: jest.fn(), + getLogs: jest.fn(), + resolveName: jest.fn(), + lookupAddress: jest.fn(), + on: jest.fn(), + once: jest.fn(), + emit: jest.fn(), + listenerCount: jest.fn(), + listeners: jest.fn(), + off: jest.fn(), + removeAllListeners: jest.fn(), + addListener: jest.fn(), + removeListener: jest.fn(), + waitForTransaction: jest.fn(), + _isProvider: true, + }); + + it("should use custom RPC URL when provided with private key", async () => { + const customRpcUrl = "https://custom-rpc.example.com"; + const mockProvider = createMockProvider(11155111, "sepolia"); + + // eslint-disable-next-line @typescript-eslint/no-var-requires + const { ethers: ethersModule } = require("ethers"); + const jsonRpcProviderSpy = jest + .spyOn(ethersModule.providers, "JsonRpcProvider") + .mockImplementation(() => mockProvider); + + await deployDocumentStore({ + storeName: "Test", + network: "sepolia", + key: "0000000000000000000000000000000000000000000000000000000000000001", + rpcUrl: customRpcUrl, + dryRun: false, + maxPriorityFeePerGasScale: 1, + } as any); + + const passedSigner: Wallet = mockedDocumentStoreFactory.mock.calls[0][0]; + expect(passedSigner.privateKey).toBe("0x0000000000000000000000000000000000000000000000000000000000000001"); + // Verify JsonRpcProvider was called with the custom RPC URL + expect(jsonRpcProviderSpy).toHaveBeenCalledWith(customRpcUrl); + + jsonRpcProviderSpy.mockRestore(); + }); + + it("should use custom RPC URL when provided with environment variable key", async () => { + process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; + const customRpcUrl = "https://another-custom-rpc.example.com"; + const mockProvider = createMockProvider(11155111, "sepolia"); + + // eslint-disable-next-line @typescript-eslint/no-var-requires + const { ethers: ethersModule } = require("ethers"); + const jsonRpcProviderSpy = jest + .spyOn(ethersModule.providers, "JsonRpcProvider") + .mockImplementation(() => mockProvider); + + await deployDocumentStore({ + storeName: "Test", + network: "sepolia", + rpcUrl: customRpcUrl, + dryRun: false, + maxPriorityFeePerGasScale: 1, + } as any); + + const passedSigner: Wallet = mockedDocumentStoreFactory.mock.calls[0][0]; + expect(passedSigner.privateKey).toBe(`0x${process.env.OA_PRIVATE_KEY}`); + // Verify JsonRpcProvider was called with the custom RPC URL + expect(jsonRpcProviderSpy).toHaveBeenCalledWith(customRpcUrl); + + jsonRpcProviderSpy.mockRestore(); + }); + + it("should use custom RPC URL when provided with key file", async () => { + const customRpcUrl = "https://keyfile-custom-rpc.example.com"; + const mockProvider = createMockProvider(11155111, "sepolia"); + + // eslint-disable-next-line @typescript-eslint/no-var-requires + const { ethers: ethersModule } = require("ethers"); + const jsonRpcProviderSpy = jest + .spyOn(ethersModule.providers, "JsonRpcProvider") + .mockImplementation(() => mockProvider); + + await deployDocumentStore({ + storeName: "Test", + network: "sepolia", + keyFile: join(__dirname, "..", "..", "..", "..", "examples", "sample-key"), + rpcUrl: customRpcUrl, + dryRun: false, + maxPriorityFeePerGasScale: 1, + } as any); + + const passedSigner: Wallet = mockedDocumentStoreFactory.mock.calls[0][0]; + expect(passedSigner.privateKey).toBe("0x0000000000000000000000000000000000000000000000000000000000000003"); + // Verify JsonRpcProvider was called with the custom RPC URL + expect(jsonRpcProviderSpy).toHaveBeenCalledWith(customRpcUrl); + + jsonRpcProviderSpy.mockRestore(); + }); + }); }); }); diff --git a/src/implementations/utils/__tests__/wallet.test.ts b/src/implementations/utils/__tests__/wallet.test.ts index d6a491cf..990be78c 100644 --- a/src/implementations/utils/__tests__/wallet.test.ts +++ b/src/implementations/utils/__tests__/wallet.test.ts @@ -1,22 +1,77 @@ import { prompt } from "inquirer"; import path from "path"; import { getWalletOrSigner } from "../wallet"; +import { getSupportedNetwork } from "../../../common/networks"; + jest.mock("inquirer"); +jest.mock("../../../common/networks"); +jest.mock("ethers", () => ({ + ...jest.requireActual("ethers"), + providers: { + ...jest.requireActual("ethers").providers, + JsonRpcProvider: jest.fn(), + }, +})); // assigning the mock so that we get correct typing // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const promptMock: jest.Mock = prompt; +const getSupportedNetworkMock = getSupportedNetwork as jest.MockedFunction; const privateKey = "0xcd27dc84c82c5814e7edac518edd5f263e7db7f25adb7a1afe13996a95583cf2"; const walletAddress = "0xB26B4941941C51a4885E5B7D3A1B861E54405f90"; +// Factory function to create mock providers with complete ethers.js provider interface +const createMockProvider = (chainId: number, name: string): any => ({ + getNetwork: jest.fn().mockResolvedValue({ chainId, name }), + getBalance: jest.fn(), + getTransactionCount: jest.fn(), + getGasPrice: jest.fn(), + estimateGas: jest.fn(), + call: jest.fn(), + sendTransaction: jest.fn(), + getBlock: jest.fn(), + getTransaction: jest.fn(), + getTransactionReceipt: jest.fn(), + getLogs: jest.fn(), + resolveName: jest.fn(), + lookupAddress: jest.fn(), + on: jest.fn(), + once: jest.fn(), + emit: jest.fn(), + listenerCount: jest.fn(), + listeners: jest.fn(), + off: jest.fn(), + removeAllListeners: jest.fn(), + addListener: jest.fn(), + removeListener: jest.fn(), + waitForTransaction: jest.fn(), + _isProvider: true, +}); + +// Mock provider for default network tests +const mockNetworkProvider = createMockProvider(11155111, "sepolia"); + describe("wallet", () => { // increase timeout because ethers is throttling jest.setTimeout(30000); + + beforeEach(() => { + // Mock the default network provider + getSupportedNetworkMock.mockReturnValue({ + provider: () => mockNetworkProvider as any, + networkId: 11155111, + networkName: "sepolia" as any, + explorer: "https://sepolia.etherscan.io", + currency: "ETH" as any, + }); + }); + afterEach(() => { delete process.env.OA_PRIVATE_KEY; promptMock.mockRestore(); + jest.clearAllMocks(); }); it("should return the wallet when providing the key using environment variable", async () => { process.env.OA_PRIVATE_KEY = privateKey; @@ -63,4 +118,86 @@ describe("wallet", () => { ) ); }); + + describe("custom RPC URL", () => { + const customRpcUrl = "https://custom-rpc.example.com"; + const mockCustomProvider = createMockProvider(1, "custom"); + + let JsonRpcProviderSpy: jest.SpyInstance; + + beforeEach(() => { + // eslint-disable-next-line @typescript-eslint/no-var-requires + const { ethers } = require("ethers"); + JsonRpcProviderSpy = jest.spyOn(ethers.providers, "JsonRpcProvider").mockImplementation(() => mockCustomProvider); + }); + + afterEach(() => { + JsonRpcProviderSpy.mockRestore(); + }); + + it("should use custom RPC URL when provided with private key", async () => { + const wallet = await getWalletOrSigner({ + network: "sepolia", + key: privateKey, + rpcUrl: customRpcUrl, + }); + + expect(JsonRpcProviderSpy).toHaveBeenCalledWith(customRpcUrl); + await expect(wallet.getAddress()).resolves.toStrictEqual(walletAddress); + expect(wallet.privateKey).toStrictEqual(privateKey); + }); + + it("should use custom RPC URL when provided with environment variable key", async () => { + process.env.OA_PRIVATE_KEY = privateKey; + + const wallet = await getWalletOrSigner({ + network: "sepolia", + rpcUrl: customRpcUrl, + }); + + expect(JsonRpcProviderSpy).toHaveBeenCalledWith(customRpcUrl); + await expect(wallet.getAddress()).resolves.toStrictEqual(walletAddress); + expect(wallet.privateKey).toStrictEqual(privateKey); + }); + + it("should use custom RPC URL when provided with key file", async () => { + const wallet = await getWalletOrSigner({ + network: "sepolia", + keyFile: path.resolve(__dirname, "./key.file"), + rpcUrl: customRpcUrl, + }); + + expect(JsonRpcProviderSpy).toHaveBeenCalledWith(customRpcUrl); + await expect(wallet.getAddress()).resolves.toStrictEqual(walletAddress); + expect(wallet.privateKey).toStrictEqual(privateKey); + }); + + it("should use custom RPC URL when provided with encrypted wallet", async () => { + promptMock.mockReturnValue({ password: "password123" }); + + const wallet = await getWalletOrSigner({ + network: "sepolia", + encryptedWalletPath: path.resolve(__dirname, "./wallet.json"), + rpcUrl: customRpcUrl, + progress: () => void 0, + }); + + expect(JsonRpcProviderSpy).toHaveBeenCalledWith(customRpcUrl); + await expect(wallet.getAddress()).resolves.toStrictEqual(walletAddress); + expect(wallet.privateKey).toStrictEqual(privateKey); + }); + + it("should prioritize custom RPC URL over network setting", async () => { + const wallet = await getWalletOrSigner({ + network: "mainnet", // Different network + key: privateKey, + rpcUrl: customRpcUrl, + }); + + // Should use custom RPC URL instead of mainnet provider + expect(JsonRpcProviderSpy).toHaveBeenCalledWith(customRpcUrl); + await expect(wallet.getAddress()).resolves.toStrictEqual(walletAddress); + expect(wallet.privateKey).toStrictEqual(privateKey); + }); + }); }); diff --git a/src/implementations/utils/wallet.ts b/src/implementations/utils/wallet.ts index ee28e603..d77b1737 100644 --- a/src/implementations/utils/wallet.ts +++ b/src/implementations/utils/wallet.ts @@ -6,9 +6,11 @@ import { addAddressPrefix } from "../../utils"; import { isAwsKmsSignerOption, + isRpcUrlOption, isWalletOption, NetworkOption, PrivateKeyOption, + RpcUrlOption, WalletOrSignerOption, } from "../../commands/shared"; import { readFile } from "./disk"; @@ -43,10 +45,13 @@ export const getWalletOrSigner = async ({ network, progress = defaultProgress("Decrypting Wallet"), ...options -}: WalletOrSignerOption & Partial & { progress?: (progress: number) => void }): Promise< - Wallet | ConnectedSigner -> => { - const provider = getSupportedNetwork(network ?? "mainnet").provider(); +}: WalletOrSignerOption & + Partial & + Partial & { progress?: (progress: number) => void }): Promise => { + // Use custom RPC URL if provided, otherwise use the default network provider + const provider = isRpcUrlOption(options) + ? new ethers.providers.JsonRpcProvider(options.rpcUrl) + : getSupportedNetwork(network ?? "mainnet").provider(); if (isWalletOption(options)) { const { password } = await inquirer.prompt({ type: "password", name: "password", message: "Wallet password" }); From 609af798e1cb201fd6c20fc8199114448a2e1a1a Mon Sep 17 00:00:00 2001 From: nghaninn <43451336+nghaninn@users.noreply.github.com> Date: Tue, 29 Jul 2025 11:21:12 +0800 Subject: [PATCH 5/7] fix: patch file --- patches/security-context+4.0.0.patch | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/patches/security-context+4.0.0.patch b/patches/security-context+4.0.0.patch index 18dd2785..79c288cd 100644 --- a/patches/security-context+4.0.0.patch +++ b/patches/security-context+4.0.0.patch @@ -1,8 +1,8 @@ diff --git a/node_modules/security-context/js/index.js b/node_modules/security-context/js/index.js -index 16048c7..e5da421 100644 +index 440b400..a0bab30 100644 --- a/node_modules/security-context/js/index.js +++ b/node_modules/security-context/js/index.js -@@ -8,10 +8,19 @@ exports.constants = constants; +@@ -8,10 +8,21 @@ exports.constants = constants; const contexts = exports.contexts = new Map(); function _read(_path) { @@ -16,7 +16,7 @@ index 16048c7..e5da421 100644 + console.error(`Security context file not found: ${filePath}`); + return {}; + } -+ const fileContent = fs.readFileSync(filePath, {encoding: 'utf8'}); ++ const fileContent = fs.readFileSync(filePath, { encoding: 'utf8' }); + if (!fileContent || fileContent === 'undefined') { + return {}; + } From 48584a1868f45b757d0e9f77f20da753b3c9344c Mon Sep 17 00:00:00 2001 From: nghaninn <43451336+nghaninn@users.noreply.github.com> Date: Tue, 29 Jul 2025 17:23:09 +0800 Subject: [PATCH 6/7] fix: revert changes on patch. resolve global mock fs error --- package-lock.json | 181 +-------------------------- package.json | 3 +- patches/security-context+4.0.0.patch | 30 ----- src/__tests__/unwrap.test.ts | 7 +- src/__tests__/wrap.test.ts | 65 ++++++++-- 5 files changed, 68 insertions(+), 218 deletions(-) delete mode 100644 patches/security-context+4.0.0.patch diff --git a/package-lock.json b/package-lock.json index 25dd08b7..4a18acf2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,7 +7,6 @@ "": { "name": "@tradetrust-tt/tradetrust-cli", "version": "0.0.0-development", - "hasInstallScript": true, "license": "GPL-3.0", "dependencies": { "@govtechsg/oa-encryption": "^1.3.5", @@ -65,7 +64,6 @@ "git-cz": "^4.7.6", "jest": "^29.7.0", "jest-watch-typeahead": "^2.2.2", - "patch-package": "^8.0.0", "pkg": "^5.8.1", "prettier": "^2.3.0", "proxyquire": "^2.1.3", @@ -8124,13 +8122,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@yarnpkg/lockfile": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", - "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", - "dev": true, - "license": "BSD-2-Clause" - }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -11557,16 +11548,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/find-yarn-workspace-root": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", - "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "micromatch": "^4.0.2" - } - }, "node_modules/findup-sync": { "version": "4.0.0", "dev": true, @@ -12901,6 +12882,8 @@ "version": "2.2.1", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "bin": { "is-docker": "cli.js" }, @@ -13241,6 +13224,8 @@ "version": "2.2.0", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "is-docker": "^2.0.0" }, @@ -14557,38 +14542,11 @@ "version": "1.0.0", "license": "MIT" }, - "node_modules/json-stable-stringify": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.3.0.tgz", - "integrity": "sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "isarray": "^2.0.5", - "jsonify": "^0.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "dev": true, "license": "MIT" }, - "node_modules/json-stable-stringify/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true, - "license": "MIT" - }, "node_modules/json-stringify-safe": { "version": "5.0.1", "license": "ISC" @@ -14619,16 +14577,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/jsonify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", - "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", - "dev": true, - "license": "Public Domain", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/jsonld": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/jsonld/-/jsonld-6.0.0.tgz", @@ -14772,16 +14720,6 @@ "node": ">=0.10.0" } }, - "node_modules/klaw-sync": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", - "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.1.11" - } - }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -18634,23 +18572,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/open": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", - "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-docker": "^2.0.0", - "is-wsl": "^2.1.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/optionator": { "version": "0.9.4", "dev": true, @@ -18850,87 +18771,6 @@ "node": ">=0.10.0" } }, - "node_modules/patch-package": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-8.0.0.tgz", - "integrity": "sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@yarnpkg/lockfile": "^1.1.0", - "chalk": "^4.1.2", - "ci-info": "^3.7.0", - "cross-spawn": "^7.0.3", - "find-yarn-workspace-root": "^2.0.0", - "fs-extra": "^9.0.0", - "json-stable-stringify": "^1.0.2", - "klaw-sync": "^6.0.0", - "minimist": "^1.2.6", - "open": "^7.4.2", - "rimraf": "^2.6.3", - "semver": "^7.5.3", - "slash": "^2.0.0", - "tmp": "^0.0.33", - "yaml": "^2.2.2" - }, - "bin": { - "patch-package": "index.js" - }, - "engines": { - "node": ">=14", - "npm": ">5" - } - }, - "node_modules/patch-package/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/patch-package/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/patch-package/node_modules/slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/patch-package/node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/path-exists": { "version": "4.0.0", "dev": true, @@ -22680,19 +22520,6 @@ "version": "3.1.1", "license": "ISC" }, - "node_modules/yaml": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", - "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", - "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - } - }, "node_modules/yargs": { "version": "17.7.2", "license": "MIT", diff --git a/package.json b/package.json index f8bf3027..a5893011 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "benchmark:run": "./scripts/benchmark.sh", "benchmark:clean": "rm -rf ./benchmark", "benchmark:full": "npm run benchmark:make-certs && npm run benchmark:run && npm run benchmark:clean", - "prepare": "patch-package && snyk-protect", + "prepare": "snyk-protect", "benchmark": "ts-node performance-tests/wrap-performance-test.ts", "pkg": "npx pkg ./package.json --out-path dist/@tradetrust-tt", "release:dryrun": "semantic-release --dry-run --no-ci" @@ -58,7 +58,6 @@ "git-cz": "^4.7.6", "jest": "^29.7.0", "jest-watch-typeahead": "^2.2.2", - "patch-package": "^8.0.0", "pkg": "^5.8.1", "prettier": "^2.3.0", "proxyquire": "^2.1.3", diff --git a/patches/security-context+4.0.0.patch b/patches/security-context+4.0.0.patch deleted file mode 100644 index 79c288cd..00000000 --- a/patches/security-context+4.0.0.patch +++ /dev/null @@ -1,30 +0,0 @@ -diff --git a/node_modules/security-context/js/index.js b/node_modules/security-context/js/index.js -index 440b400..a0bab30 100644 ---- a/node_modules/security-context/js/index.js -+++ b/node_modules/security-context/js/index.js -@@ -8,10 +8,21 @@ exports.constants = constants; - const contexts = exports.contexts = new Map(); - - function _read(_path) { -- return JSON.parse( -- fs.readFileSync( -- path.join(__dirname, _path), -- {encoding: 'utf8'})); -+ try { -+ const filePath = path.join(__dirname, _path); -+ if (!fs.existsSync(filePath)) { -+ console.error(`Security context file not found: ${filePath}`); -+ return {}; -+ } -+ const fileContent = fs.readFileSync(filePath, { encoding: 'utf8' }); -+ if (!fileContent || fileContent === 'undefined') { -+ return {}; -+ } -+ return JSON.parse(fileContent); -+ } catch (error) { -+ console.error(`Error parsing security context file: ${_path}`, error); -+ return {}; -+ } - } - - contexts.set( diff --git a/src/__tests__/unwrap.test.ts b/src/__tests__/unwrap.test.ts index 56276b35..b391a31f 100644 --- a/src/__tests__/unwrap.test.ts +++ b/src/__tests__/unwrap.test.ts @@ -6,8 +6,7 @@ import wrappedFileFixture1 from "./fixture/2.0/wrapped-example.1.json"; import unwrappedFileFixture1 from "./fixture/2.0/unwrapped-example.1.json"; import wrappedFileFixture2 from "./fixture/2.0/wrapped-example.2.json"; import unwrappedFileFixture2 from "./fixture/2.0/unwrapped-example.2.json"; - -jest.mock("fs"); +import * as disk from "../implementations/utils/disk"; describe("unwrap", () => { describe("unwrapIndividualDocuments", () => { @@ -35,6 +34,7 @@ describe("unwrap", () => { } throw new Error(`unhandled ${path} in spy`); }); + jest.spyOn(disk, "documentsInDirectory").mockResolvedValue(["./fixture/2.0/wrapped-example.1.json"]); const unwrappedDocumentCount = await unwrapIndividualDocuments( "./fixture/2.0", @@ -80,6 +80,9 @@ describe("unwrap", () => { } throw new Error(`unhandled ${path} in spy`); }); + jest + .spyOn(disk, "documentsInDirectory") + .mockResolvedValue(["./fixture/2.0/wrapped-example.1.json", "./fixture/2.0/wrapped-example.2.json"]); const unwrappedDocumentCount = await unwrapIndividualDocuments( "./fixture/2.0", diff --git a/src/__tests__/wrap.test.ts b/src/__tests__/wrap.test.ts index 98b63e4c..a1eeda3b 100644 --- a/src/__tests__/wrap.test.ts +++ b/src/__tests__/wrap.test.ts @@ -1,28 +1,79 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ import { appendProofToDocuments, merkleHashmap } from "../implementations/wrap"; import { Output } from "../implementations/utils/disk"; +import * as disk from "../implementations/utils/disk"; import fs from "fs"; +import util from "util"; import { utils } from "@tradetrust-tt/tradetrust"; -jest.mock("fs"); - describe("batchIssue", () => { describe("appendProofToDocuments", () => { it("determines the proof for each document using the hashmap and writes the new document back", async () => { - expect.assertions(4); // make sure there are 4 assertions because some assertions are made in fs.spyOn const hashMap = { a: { sibling: "b", parent: "d" }, b: { sibling: "a", parent: "d" }, c: { sibling: "d", parent: "e" }, d: { sibling: "c", parent: "e" }, }; - // @ts-ignore - jest.spyOn(fs, "lstatSync").mockReturnValue({ isDirectory: () => true }); - jest.spyOn(fs, "readdir").mockImplementation((options, callback) => { + + // Mock fs.lstatSync to always return a directory + jest.spyOn(fs, "lstatSync").mockImplementation((): any => { + console.log("🚀 ~ isDirectory:"); + return { + isDirectory: (): boolean => { + console.log("🚀 ~ isDirectory:"); + return true; + }, + }; + }); + + // Mock readdirSync for synchronous calls + jest.spyOn(fs, "readdirSync").mockImplementation((): any => { + console.log("🚀 ~ fs ~ readdirSync:"); + return ["file_1.json", "file_2.json", "file_3.json"]; + }); + + // Create a mock implementation that will be used by the promisified version + const mockReaddirImpl = jest.fn().mockImplementation((path: any, options: any, callback: any) => { + console.log("🚀 ~ DIRECT fs.readdir called with path:", path); + + // Handle both callback style and promisified style + if (typeof options === "function") { + callback = options; + options = undefined; + } + + if (callback) { + // Ensure callback is called asynchronously to better simulate real behavior + process.nextTick(() => { + callback(null, ["file_1.json", "file_2.json", "file_3.json"]); + }); + } + return undefined; + }); + + // Replace the fs.readdir implementation + jest.spyOn(fs, "readdir").mockImplementation(mockReaddirImpl); + + // Mock promisify to return our custom implementation for fs.readdir + jest.spyOn(util, "promisify").mockImplementation((fn) => { + console.log("🚀 ~ promisify:"); + if (fn === fs.readdir) { + console.log("🚀 ~ promisifying fs.readdir"); + return jest.fn().mockResolvedValue(["file_1.json", "file_2.json", "file_3.json"]); + } + // Fall back to original for other functions // @ts-ignore - return callback(null, ["file_1.json", "file_2.json", "file_3.json"]); + return jest.requireActual("util").promisify(fn); }); + + // // Ensure documentsInDirectory gets mocked directly to bypass any fs issues + jest + .spyOn(disk, "documentsInDirectory") + .mockResolvedValue(["DIR/file_1.json", "DIR/file_2.json", "DIR/file_3.json"]); + jest.spyOn(fs, "readFileSync").mockImplementation((path) => { + console.log("🚀 ~ readFileSync:", path); // @ts-ignore if (path.includes("file_1.json")) { return JSON.stringify({ From de62f1840254652546b1dbf53e9b604d7c464c67 Mon Sep 17 00:00:00 2001 From: nghaninn <43451336+nghaninn@users.noreply.github.com> Date: Tue, 29 Jul 2025 17:41:15 +0800 Subject: [PATCH 7/7] fix: mock fs to limited function --- src/__tests__/unwrap.test.ts | 13 ++++--- src/__tests__/wrap.test.ts | 72 +++++++----------------------------- 2 files changed, 22 insertions(+), 63 deletions(-) diff --git a/src/__tests__/unwrap.test.ts b/src/__tests__/unwrap.test.ts index b391a31f..a2eba138 100644 --- a/src/__tests__/unwrap.test.ts +++ b/src/__tests__/unwrap.test.ts @@ -6,7 +6,14 @@ import wrappedFileFixture1 from "./fixture/2.0/wrapped-example.1.json"; import unwrappedFileFixture1 from "./fixture/2.0/unwrapped-example.1.json"; import wrappedFileFixture2 from "./fixture/2.0/wrapped-example.2.json"; import unwrappedFileFixture2 from "./fixture/2.0/unwrapped-example.2.json"; -import * as disk from "../implementations/utils/disk"; +jest.mock("fs", () => { + return { + ...jest.requireActual("fs"), + readdir: jest.fn(), + lstatSync: jest.fn(), + writeFileSync: jest.fn(), + }; +}); describe("unwrap", () => { describe("unwrapIndividualDocuments", () => { @@ -34,7 +41,6 @@ describe("unwrap", () => { } throw new Error(`unhandled ${path} in spy`); }); - jest.spyOn(disk, "documentsInDirectory").mockResolvedValue(["./fixture/2.0/wrapped-example.1.json"]); const unwrappedDocumentCount = await unwrapIndividualDocuments( "./fixture/2.0", @@ -80,9 +86,6 @@ describe("unwrap", () => { } throw new Error(`unhandled ${path} in spy`); }); - jest - .spyOn(disk, "documentsInDirectory") - .mockResolvedValue(["./fixture/2.0/wrapped-example.1.json", "./fixture/2.0/wrapped-example.2.json"]); const unwrappedDocumentCount = await unwrapIndividualDocuments( "./fixture/2.0", diff --git a/src/__tests__/wrap.test.ts b/src/__tests__/wrap.test.ts index a1eeda3b..df34d60f 100644 --- a/src/__tests__/wrap.test.ts +++ b/src/__tests__/wrap.test.ts @@ -1,79 +1,35 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ import { appendProofToDocuments, merkleHashmap } from "../implementations/wrap"; import { Output } from "../implementations/utils/disk"; -import * as disk from "../implementations/utils/disk"; import fs from "fs"; -import util from "util"; import { utils } from "@tradetrust-tt/tradetrust"; +jest.mock("fs", () => { + return { + ...jest.requireActual("fs"), + readdir: jest.fn(), + lstatSync: jest.fn(), + writeFileSync: jest.fn(), + }; +}); + describe("batchIssue", () => { describe("appendProofToDocuments", () => { it("determines the proof for each document using the hashmap and writes the new document back", async () => { + expect.assertions(4); // make sure there are 4 assertions because some assertions are made in fs.spyOn const hashMap = { a: { sibling: "b", parent: "d" }, b: { sibling: "a", parent: "d" }, c: { sibling: "d", parent: "e" }, d: { sibling: "c", parent: "e" }, }; - - // Mock fs.lstatSync to always return a directory - jest.spyOn(fs, "lstatSync").mockImplementation((): any => { - console.log("🚀 ~ isDirectory:"); - return { - isDirectory: (): boolean => { - console.log("🚀 ~ isDirectory:"); - return true; - }, - }; - }); - - // Mock readdirSync for synchronous calls - jest.spyOn(fs, "readdirSync").mockImplementation((): any => { - console.log("🚀 ~ fs ~ readdirSync:"); - return ["file_1.json", "file_2.json", "file_3.json"]; - }); - - // Create a mock implementation that will be used by the promisified version - const mockReaddirImpl = jest.fn().mockImplementation((path: any, options: any, callback: any) => { - console.log("🚀 ~ DIRECT fs.readdir called with path:", path); - - // Handle both callback style and promisified style - if (typeof options === "function") { - callback = options; - options = undefined; - } - - if (callback) { - // Ensure callback is called asynchronously to better simulate real behavior - process.nextTick(() => { - callback(null, ["file_1.json", "file_2.json", "file_3.json"]); - }); - } - return undefined; - }); - - // Replace the fs.readdir implementation - jest.spyOn(fs, "readdir").mockImplementation(mockReaddirImpl); - - // Mock promisify to return our custom implementation for fs.readdir - jest.spyOn(util, "promisify").mockImplementation((fn) => { - console.log("🚀 ~ promisify:"); - if (fn === fs.readdir) { - console.log("🚀 ~ promisifying fs.readdir"); - return jest.fn().mockResolvedValue(["file_1.json", "file_2.json", "file_3.json"]); - } - // Fall back to original for other functions + // @ts-ignore + jest.spyOn(fs, "lstatSync").mockReturnValue({ isDirectory: () => true }); + jest.spyOn(fs, "readdir").mockImplementation((options, callback) => { // @ts-ignore - return jest.requireActual("util").promisify(fn); + return callback(null, ["file_1.json", "file_2.json", "file_3.json"]); }); - - // // Ensure documentsInDirectory gets mocked directly to bypass any fs issues - jest - .spyOn(disk, "documentsInDirectory") - .mockResolvedValue(["DIR/file_1.json", "DIR/file_2.json", "DIR/file_3.json"]); - jest.spyOn(fs, "readFileSync").mockImplementation((path) => { - console.log("🚀 ~ readFileSync:", path); // @ts-ignore if (path.includes("file_1.json")) { return JSON.stringify({