@ethernity-cloud/sdk-js 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/init.js +49 -0
- package/nodenithy/build/securelock/Dockerfile.tmpl +5 -0
- package/nodenithy/build/securelock/src/ecld_state.js +304 -0
- package/nodenithy/build/securelock/src/esr_wallet.js +147 -0
- package/nodenithy/build/securelock/src/etny_crypto.js +211 -201
- package/nodenithy/build/securelock/src/etny_exec.js +22 -0
- package/nodenithy/build/securelock/src/securelock.js.tmpl +115 -12
- package/nodenithy/build/securelock/src/task_status.js +4 -0
- package/nodenithy/build.mjs +19 -1
- package/nodenithy/run/public_key_service.js +11 -0
- package/nodenithy/run.js +22 -0
- package/package.json +49 -49
|
@@ -11,6 +11,10 @@ class TaskStatus {
|
|
|
11
11
|
// Extended diagnostic (matches the trustedzone's extended enum): the
|
|
12
12
|
// serverless backend failed to load, so none of its functions exist.
|
|
13
13
|
static IMPORT_ERROR = 28;
|
|
14
|
+
// A required enclave config value is present but EMPTY (e.g. an ESR
|
|
15
|
+
// address that was never baked into the sealed image). Reported eagerly
|
|
16
|
+
// with the variable named, instead of a confusing downstream crash.
|
|
17
|
+
static CONFIG_ERROR = 32;
|
|
14
18
|
}
|
|
15
19
|
|
|
16
20
|
module.exports = {
|
package/nodenithy/build.mjs
CHANGED
|
@@ -156,9 +156,27 @@ if (!fs.existsSync('src/sgx_report.node')) {
|
|
|
156
156
|
console.error(' securelock/src/ (see src/README-keygen.md) before building.');
|
|
157
157
|
process.exit(1);
|
|
158
158
|
}
|
|
159
|
+
// ESR fail-fast gate (RFC §5.4), mirroring the Python SDK's validate_esr_config:
|
|
160
|
+
// never build an ESR-enabled enclave with an unresolved registry address. The
|
|
161
|
+
// enclave is SEALED -- a missing value bakes in as empty, and every task then
|
|
162
|
+
// fails at runtime after gas is already spent. ESR is opt-in: absent/false
|
|
163
|
+
// ESR_ENABLED means the build behaves exactly as it did before ESR existed.
|
|
164
|
+
const ESR_ENABLED = /^(1|true|yes)$/i.test(String(process.env.ESR_ENABLED || '').trim());
|
|
165
|
+
const ESR_CONTRACT_ADDRESS = String(process.env.ESR_CONTRACT_ADDRESS || '').trim();
|
|
166
|
+
if (ESR_ENABLED && !/^0x[0-9a-fA-F]{40}$/.test(ESR_CONTRACT_ADDRESS)) {
|
|
167
|
+
console.error('ERROR: ESR is enabled but ESR_CONTRACT_ADDRESS is not a valid address'
|
|
168
|
+
+ ` (got ${JSON.stringify(ESR_CONTRACT_ADDRESS)}).`);
|
|
169
|
+
console.error(' The enclave is sealed: a missing value bakes in as EMPTY and every');
|
|
170
|
+
console.error(' task fails at runtime after gas is spent. Set it with:');
|
|
171
|
+
console.error(' ecld-init (ESR step) or ESR_CONTRACT_ADDRESS in .env');
|
|
172
|
+
process.exit(1);
|
|
173
|
+
}
|
|
174
|
+
// Rendered only when enabled, so non-ESR images keep byte-identical layers.
|
|
175
|
+
const esrEnvBlock = ESR_ENABLED ? `ENV ESR_CONTRACT_ADDRESS=${ESR_CONTRACT_ADDRESS}` : '';
|
|
176
|
+
|
|
159
177
|
// runCommand(`cat Dockerfile.tmpl | sed s/"__ENCLAVE_NAME_SECURELOCK__"/"${ENCLAVE_NAME_SECURELOCK}"/g > Dockerfile`);
|
|
160
178
|
const dockerfileSecureTemplate = fs.readFileSync('Dockerfile.tmpl', 'utf8');
|
|
161
|
-
let dockerfileSecureContent = dockerfileSecureTemplate.replace(/__ENCLAVE_NAME_SECURELOCK__/g, ENCLAVE_NAME_SECURELOCK).replace(/__BUCKET_NAME__/g, templateName + "-v3").replace(/__SMART_CONTRACT_ADDRESS__/g, ECRunner[templateName][0]).replace(/__IMAGE_REGISTRY_ADDRESS__/g, ECRunner[templateName][1]).replace(/__RPC_URL__/g, ECRunner[templateName][2]).replace(/__CHAIN_ID__/g, ECRunner[templateName][3]).replace(/__TRUSTED_ZONE_IMAGE__/g, templateName);
|
|
179
|
+
let dockerfileSecureContent = dockerfileSecureTemplate.replace(/__ENCLAVE_NAME_SECURELOCK__/g, ENCLAVE_NAME_SECURELOCK).replace(/__BUCKET_NAME__/g, templateName + "-v3").replace(/__SMART_CONTRACT_ADDRESS__/g, ECRunner[templateName][0]).replace(/__IMAGE_REGISTRY_ADDRESS__/g, ECRunner[templateName][1]).replace(/__RPC_URL__/g, ECRunner[templateName][2]).replace(/__CHAIN_ID__/g, ECRunner[templateName][3]).replace(/__TRUSTED_ZONE_IMAGE__/g, templateName).replace(/^__ESR_ENV__\n/m, esrEnvBlock ? `${esrEnvBlock}\n` : '');
|
|
162
180
|
|
|
163
181
|
// Amount of enclave heap to allocate (SCONE_HEAP). Kept in sync with the
|
|
164
182
|
// run/docker-compose securelock service; overridable via ECLD_MEMORY_TO_ALLOCATE.
|
|
@@ -78,6 +78,17 @@ console.log("Docker Composer Hash:", dockerComposerHash);
|
|
|
78
78
|
console.log("Public Key:", checkResponse.publicKey);
|
|
79
79
|
// Save public key to file
|
|
80
80
|
fs.writeFileSync('PUBLIC_KEY.txt', checkResponse.publicKey);
|
|
81
|
+
// ESR (RFC §5.2): the enclave also prints ESR_WALLET_ADDRESS on the
|
|
82
|
+
// cert channel. The service currently returns only "publicKey"; when
|
|
83
|
+
// it starts relaying the enclave's output (or adds an
|
|
84
|
+
// "esrWalletAddress" field) it is picked up here and written to a
|
|
85
|
+
// sibling file the caller reads -- no other changes needed. Until
|
|
86
|
+
// then, ESR projects extract locally on an SGX host once to learn
|
|
87
|
+
// the address (publish then persists it).
|
|
88
|
+
if (checkResponse.esrWalletAddress) {
|
|
89
|
+
console.log("ESR Wallet Address:", checkResponse.esrWalletAddress);
|
|
90
|
+
fs.writeFileSync('ESR_WALLET_ADDRESS.txt', checkResponse.esrWalletAddress);
|
|
91
|
+
}
|
|
81
92
|
break;
|
|
82
93
|
}
|
|
83
94
|
} else {
|
package/nodenithy/run.js
CHANGED
|
@@ -497,6 +497,28 @@ const main = async () => {
|
|
|
497
497
|
console.error("Error: Could not fetch PUBLIC_KEY_SECURELOCK");
|
|
498
498
|
process.exit(1);
|
|
499
499
|
}
|
|
500
|
+
// ESR (RFC §5.2): if the extraction relayed the enclave's ESR wallet
|
|
501
|
+
// address (public_key_service writes ESR_WALLET_ADDRESS.txt when the
|
|
502
|
+
// service provides it), persist it to .env so a dApp can read/fund the
|
|
503
|
+
// enclave wallet. Absent file => not an ESR project, or the (mainnet)
|
|
504
|
+
// address must be learned from a local SGX extraction — either way,
|
|
505
|
+
// silently skip. Parity with the Python SDK's esr.wallet_address.
|
|
506
|
+
try {
|
|
507
|
+
if (fs.existsSync('ESR_WALLET_ADDRESS.txt')) {
|
|
508
|
+
const esrAddr = fs.readFileSync('ESR_WALLET_ADDRESS.txt', 'utf8').trim();
|
|
509
|
+
if (/^0x[0-9a-fA-F]{40}$/.test(esrAddr)) {
|
|
510
|
+
writeEnv('ESR_WALLET_ADDRESS', esrAddr);
|
|
511
|
+
console.log(`ESR_WALLET_ADDRESS: ${esrAddr}`);
|
|
512
|
+
// Manual funding by the data owner is the default path;
|
|
513
|
+
// publishing never transfers value on its own. Say so, or
|
|
514
|
+
// the first task needing gas fails with no clue why.
|
|
515
|
+
console.log(' This wallet starts EMPTY. Fund it from your own wallet with');
|
|
516
|
+
console.log(' whatever your payload needs; publishing never transfers value.');
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
} catch (e) {
|
|
520
|
+
console.warn(`Could not persist ESR_WALLET_ADDRESS: ${e && e.message ? e.message : e}`);
|
|
521
|
+
}
|
|
500
522
|
};
|
|
501
523
|
}
|
|
502
524
|
|
package/package.json
CHANGED
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@ethernity-cloud/sdk-js",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "A package to run ethernity cloud build scripts",
|
|
5
|
-
"scripts": {
|
|
6
|
-
"ecld-build": "cross-env node ./node_modules/@ethernity-cloud/sdk-js/build.js",
|
|
7
|
-
"ecld-publish": "cross-env node ./node_modules/@ethernity-cloud/sdk-js/publish.js",
|
|
8
|
-
"ecld-init": "cross-env node ./node_modules/@ethernity-cloud/sdk-js/init.js",
|
|
9
|
-
"ecld-run": "cross-env ecld-run",
|
|
10
|
-
"postinstall": "node postinstall.js",
|
|
11
|
-
"ecld-test": "cross-env node ./node_modules/@ethernity-cloud/sdk-js/test.js"
|
|
12
|
-
},
|
|
13
|
-
"bin": {
|
|
14
|
-
"ecld-build": "./build.js",
|
|
15
|
-
"ecld-publish": "./publish.js",
|
|
16
|
-
"ecld-init": "./init.js",
|
|
17
|
-
"postinstall": "./postinstall.js",
|
|
18
|
-
"ecld-test": "./test.js"
|
|
19
|
-
},
|
|
20
|
-
"files": [
|
|
21
|
-
"nodenithy/*",
|
|
22
|
-
"pynithy/*",
|
|
23
|
-
"build.js",
|
|
24
|
-
"init.js",
|
|
25
|
-
"publish.js",
|
|
26
|
-
"postinstall.js"
|
|
27
|
-
],
|
|
28
|
-
"dependencies": {
|
|
29
|
-
"@ethernity-cloud/runner": "^0.0.26",
|
|
30
|
-
"axios": "^1.7.2",
|
|
31
|
-
"commander": "^12.1.0",
|
|
32
|
-
"dotenv": "^16.4.5",
|
|
33
|
-
"eth-lib": "^0.1.29",
|
|
34
|
-
"ethers": "^5.5.4",
|
|
35
|
-
"kubo-rpc-client": "^4.1.1",
|
|
36
|
-
"web3": "^4.9.0",
|
|
37
|
-
"cross-env": "^7.0.3",
|
|
38
|
-
"shelljs": "^0.8.5",
|
|
39
|
-
"shx": "^0.3.4",
|
|
40
|
-
"node-forge": "^1.3.1",
|
|
41
|
-
"cli-progress": "^3.12.0",
|
|
42
|
-
"react": "^18.3.1",
|
|
43
|
-
"react-dom": "^18.3.1",
|
|
44
|
-
"react-scripts": "^5.0.1",
|
|
45
|
-
"web-vitals": "^2.1.4",
|
|
46
|
-
"adm-zip": "^0.5.14"
|
|
47
|
-
},
|
|
48
|
-
"author": "Alexandru Luca",
|
|
49
|
-
"license": "AGPL-3.0"
|
|
1
|
+
{
|
|
2
|
+
"name": "@ethernity-cloud/sdk-js",
|
|
3
|
+
"version": "1.5.0",
|
|
4
|
+
"description": "A package to run ethernity cloud build scripts",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"ecld-build": "cross-env node ./node_modules/@ethernity-cloud/sdk-js/build.js",
|
|
7
|
+
"ecld-publish": "cross-env node ./node_modules/@ethernity-cloud/sdk-js/publish.js",
|
|
8
|
+
"ecld-init": "cross-env node ./node_modules/@ethernity-cloud/sdk-js/init.js",
|
|
9
|
+
"ecld-run": "cross-env ecld-run",
|
|
10
|
+
"postinstall": "node postinstall.js",
|
|
11
|
+
"ecld-test": "cross-env node ./node_modules/@ethernity-cloud/sdk-js/test.js"
|
|
12
|
+
},
|
|
13
|
+
"bin": {
|
|
14
|
+
"ecld-build": "./build.js",
|
|
15
|
+
"ecld-publish": "./publish.js",
|
|
16
|
+
"ecld-init": "./init.js",
|
|
17
|
+
"postinstall": "./postinstall.js",
|
|
18
|
+
"ecld-test": "./test.js"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"nodenithy/*",
|
|
22
|
+
"pynithy/*",
|
|
23
|
+
"build.js",
|
|
24
|
+
"init.js",
|
|
25
|
+
"publish.js",
|
|
26
|
+
"postinstall.js"
|
|
27
|
+
],
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@ethernity-cloud/runner": "^0.0.26",
|
|
30
|
+
"axios": "^1.7.2",
|
|
31
|
+
"commander": "^12.1.0",
|
|
32
|
+
"dotenv": "^16.4.5",
|
|
33
|
+
"eth-lib": "^0.1.29",
|
|
34
|
+
"ethers": "^5.5.4",
|
|
35
|
+
"kubo-rpc-client": "^4.1.1",
|
|
36
|
+
"web3": "^4.9.0",
|
|
37
|
+
"cross-env": "^7.0.3",
|
|
38
|
+
"shelljs": "^0.8.5",
|
|
39
|
+
"shx": "^0.3.4",
|
|
40
|
+
"node-forge": "^1.3.1",
|
|
41
|
+
"cli-progress": "^3.12.0",
|
|
42
|
+
"react": "^18.3.1",
|
|
43
|
+
"react-dom": "^18.3.1",
|
|
44
|
+
"react-scripts": "^5.0.1",
|
|
45
|
+
"web-vitals": "^2.1.4",
|
|
46
|
+
"adm-zip": "^0.5.14"
|
|
47
|
+
},
|
|
48
|
+
"author": "Alexandru Luca",
|
|
49
|
+
"license": "AGPL-3.0"
|
|
50
50
|
}
|