@ethernity-cloud/sdk-js 1.6.1 → 1.7.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.
Files changed (52) hide show
  1. package/README.md +44 -6
  2. package/cas/config.js +61 -3
  3. package/info.js +333 -324
  4. package/init.js +20 -4
  5. package/nodenithy/build/securelock/Dockerfile.tmpl +34 -32
  6. package/nodenithy/build/securelock/scripts/binary-fs-build.sh +7 -6
  7. package/nodenithy/build/securelock/src/securelock.js.tmpl +5 -2
  8. package/nodenithy/build.mjs +83 -71
  9. package/nodenithy/run/docker-compose-final.yml.tmpl +36 -31
  10. package/nodenithy/run/docker-compose.yml.tmpl +34 -45
  11. package/nodenithy/run/image_registry.js +396 -380
  12. package/nodenithy/run.js +42 -28
  13. package/package.json +5 -3
  14. package/publish.js +4 -2
  15. package/pynithy/build/securelock/Dockerfile.base.tpl +13 -0
  16. package/pynithy/build/securelock/Dockerfile.tpl +131 -0
  17. package/pynithy/build/securelock/scripts/binary-fs-build.sh +25 -34
  18. package/pynithy/build/securelock/scripts/pyfreeze.sh +32 -0
  19. package/pynithy/build/securelock/src/{pox.abi → abi/etnyImplementationV2.abi} +1489 -1489
  20. package/pynithy/build/securelock/src/abi/image_registry.abi +1 -0
  21. package/pynithy/build/securelock/src/ecld_state.py +906 -0
  22. package/pynithy/build/securelock/src/esr.abi +1 -0
  23. package/pynithy/build/securelock/src/esr_local.py +267 -0
  24. package/pynithy/build/securelock/src/esr_wallet.py +150 -0
  25. package/pynithy/build/securelock/src/etny_crypto.py +208 -167
  26. package/pynithy/build/securelock/src/etny_exec.py +385 -79
  27. package/pynithy/build/securelock/src/etny_exec_flask.py +535 -0
  28. package/pynithy/build/securelock/src/etny_exec_serv.py +353 -0
  29. package/pynithy/build/securelock/src/etny_session_exec.py +245 -0
  30. package/pynithy/build/securelock/src/get_sgx_report.so +0 -0
  31. package/pynithy/build/securelock/src/image_registry.abi +1 -1
  32. package/pynithy/build/securelock/src/key_generation.py +17 -17
  33. package/pynithy/build/securelock/src/local_api.py +189 -0
  34. package/pynithy/build/securelock/src/models.py +200 -176
  35. package/pynithy/build/securelock/src/securelock.py.tmpl +1037 -727
  36. package/pynithy/build/securelock/src/swift_stream_service.py +206 -186
  37. package/pynithy/build.mjs +142 -92
  38. package/pynithy/run/docker-compose-final.yml.tmpl +58 -51
  39. package/pynithy/run/docker-compose.yml.tmpl +62 -48
  40. package/pynithy/run/etny-securelock-test.yaml.tpl +4 -1
  41. package/pynithy/run/image_registry.js +396 -380
  42. package/pynithy/run.js +44 -28
  43. package/pynithy/src/serverless/Dockerfile.serverless +8 -0
  44. package/pynithy/src/serverless/requirements.txt +6 -0
  45. package/run.js +69 -28
  46. package/nodenithy/build/las/Dockerfile +0 -5
  47. package/pynithy/build/docker-compose.yml +0 -70
  48. package/pynithy/build/las/Dockerfile +0 -11
  49. package/pynithy/build/las/src/etny_entrypoint.sh +0 -6
  50. package/pynithy/build/las/src/las_entrypoint.sh +0 -26
  51. package/pynithy/build/scripts/binary-fs-build.sh +0 -28
  52. package/pynithy/build/securelock/Dockerfile.tmpl +0 -95
package/init.js CHANGED
@@ -2,6 +2,7 @@ const fs = require("fs");
2
2
  const readline = require("readline");
3
3
  const { spawn, execSync } = require("child_process");
4
4
  const path = require("path");
5
+ const casConfig = require("./cas/config.js");
5
6
 
6
7
  const rl = readline.createInterface({
7
8
  input: process.stdin,
@@ -179,6 +180,8 @@ const main = async () => {
179
180
  "IoTeX Testnet",
180
181
  "Ethereum Sepolia",
181
182
  "LitVM LiteForge",
183
+ "Bloxberg Testnet Unsafe",
184
+ "LitVM LiteForge Unsafe",
182
185
  ];
183
186
  const blockchainNetwork = await promptOptions(
184
187
  "On which Blockchain network do you want to have the app set up, as a starting point? (default is Bloxberg Testnet): ",
@@ -186,9 +189,20 @@ const main = async () => {
186
189
  "Bloxberg Testnet",
187
190
  );
188
191
  console.log();
192
+ const network = blockchainNetwork.replace(/ /g, "_");
193
+ if (casConfig.isUnsafeNetwork(network)) {
194
+ const sibling = casConfig.UNSAFE_NETWORKS[network].replace(/_/g, " ");
195
+ console.log(`${blockchainNetwork} runs your dApp WITHOUT a CAS, on the chain and contracts of ${sibling},`);
196
+ console.log("for SGX platforms the CAS cannot attest (EPID-only, SGX1). Its enclaves are debug-signed and");
197
+ console.log("sign their own certificates from their measurement: a result proves which image ran, not that");
198
+ console.log(`an enclave ran it. The securelock is registered as <project>-unsafe; choose ${sibling} for`);
199
+ console.log("a CAS-attested run.");
200
+ console.log();
201
+ }
202
+ const imageName = casConfig.nameOnNetwork(projectName.replace(/ /g, "-"), network);
189
203
 
190
204
  console.log(
191
- `Checking if the project name (image name) is available on the ${blockchainNetwork.replace(/ /g, "_")} network and ownership...`,
205
+ `Checking if the project name (image name ${imageName}) is available on the ${network} network and ownership...`,
192
206
  );
193
207
  // const { execSync } = require('child_process');
194
208
  // execSync(`python $(pwd)/node_modules/@ethernity-cloud/sdk-js/nodenithy/run/image_registry.py "${blockchainNetwork.replace(/ /g, "_")}" "${projectName.replace(/ /g, "-")}" v3`);
@@ -198,8 +212,8 @@ const main = async () => {
198
212
  new Promise((resolve, reject) => {
199
213
  const child = spawn("node", [
200
214
  scriptPath,
201
- blockchainNetwork.replace(/ /g, "_"),
202
- projectName.replace(/ /g, "-"),
215
+ network,
216
+ imageName,
203
217
  "v3",
204
218
  ]);
205
219
  // Handle stdout data
@@ -342,12 +356,14 @@ const main = async () => {
342
356
  "IoTeX Testnet": `ecld-${svc}-iotex-testnet`,
343
357
  "Ethereum Sepolia": `ecld-${svc}-ethereum-sepolia`,
344
358
  "LitVM LiteForge": `ecld-${svc}-litvm-testnet`,
359
+ "Bloxberg Testnet Unsafe": `etny-${svc}-testnet-unsafe`,
360
+ "LitVM LiteForge Unsafe": `ecld-${svc}-litvm-testnet-unsafe`,
345
361
  };
346
362
  const trustedZoneImage = imageByNetwork[blockchainNetwork] || `etny-${svc}-testnet`;
347
363
  writeEnv("TRUSTED_ZONE_IMAGE", trustedZoneImage);
348
364
 
349
365
 
350
- writeEnv("BLOCKCHAIN_NETWORK", blockchainNetwork.replace(/ /g, "_"));
366
+ writeEnv("BLOCKCHAIN_NETWORK", network);
351
367
  writeEnv("IPFS_ENDPOINT", customUrl);
352
368
  console.log();
353
369
  await configureEsr();
@@ -1,20 +1,35 @@
1
- FROM registry.ethernity.cloud:443/debuggingdelight/ethernity-cloud-sdk-registry/ethernity/node:16.13.1-alpine3.15-scone5.8-production as release
1
+ # SCONE_NODE (build.mjs passes it) is the nodenithy trustedzone image this
2
+ # securelock is bundled with: node:22-alpine with the SCONE 6.0.7 runtime and
3
+ # CLI (sconecuratedimages/node:node-22-alpine, the base the etny-nodenithy CI
4
+ # builds the trustedzones on), the release the trustedzones, the LAS and the
5
+ # CAS run. Its own enclave is replaced below: /lib/libbinary-fs.so is
6
+ # overwritten and /usr/local/bin/node re-signed.
7
+ ARG SCONE_NODE
8
+
9
+ # The dependencies are plain JavaScript, installed with a stock node of the
10
+ # same major version; no SCONE binary runs at build time.
11
+ FROM node:22-alpine AS deps
2
12
 
3
- RUN apk update
4
-
5
- RUN cd /
13
+ COPY ./src /etny-securelock/
14
+ WORKDIR /etny-securelock
15
+ RUN npm install
6
16
 
7
- RUN apk add bash
17
+ FROM ${SCONE_NODE} AS release
8
18
 
9
- ENV SCONE_HEAP=256M
19
+ # As in the runtime release stage: the scone CLI below runs on a build host
20
+ # without SGX.
21
+ ENV SCONE_MODE=SIM
10
22
  ENV SCONE_LOG=DEBUG
11
23
  ENV ENCLAVE_NAME_SECURELOCK=__ENCLAVE_NAME_SECURELOCK__
24
+ # "mainnet" or "testnet": the securelock self-signs from MR_ENCLAVE on a
25
+ # testnet without a ValidatorRegistry, and takes its certificate from the CAS
26
+ # otherwise.
27
+ ENV NETWORK_TYPE=__NETWORK_TYPE__
12
28
  ENV BUCKET_NAME=__BUCKET_NAME__
13
29
  ENV SMART_CONTRACT_ADDRESS=__SMART_CONTRACT_ADDRESS__
14
30
  ENV IMAGE_REGISTRY_ADDRESS=__IMAGE_REGISTRY_ADDRESS__
15
31
  ENV RPC_URL=__RPC_URL__
16
32
  ENV CHAIN_ID=__CHAIN_ID__
17
- ENV TRUSTED_ZONE_IMAGE=__TRUSTED_ZONE_IMAGE__
18
33
  ENV VALIDATOR_REGISTRY_ADDRESS=__ETNY_VALIDATOR_REGISTRY_ADDRESS__
19
34
  # ESR (RFC §5.4): rendered by build.mjs to `ENV ESR_CONTRACT_ADDRESS=0x...` only
20
35
  # when ESR is enabled, and to nothing otherwise -- so non-ESR images keep exactly
@@ -22,36 +37,25 @@ ENV VALIDATOR_REGISTRY_ADDRESS=__ETNY_VALIDATOR_REGISTRY_ADDRESS__
22
37
  # gates all ESR behaviour on this variable being non-empty.
23
38
  __ESR_ENV__
24
39
 
25
- RUN mkdir binary-fs-dir
40
+ RUN mkdir /binary-fs-dir
26
41
 
27
- COPY ./src /etny-securelock/
42
+ COPY --from=deps /etny-securelock /etny-securelock/
28
43
  COPY scripts/* /etny-securelock/
29
44
 
30
- WORKDIR /etny-securelock
31
- RUN pwd
32
- RUN npm install
33
- RUN ls
34
-
35
45
  WORKDIR /
36
46
 
37
47
  RUN ["chmod", "+x", "etny-securelock/binary-fs-build.sh"]
38
48
  RUN etny-securelock/binary-fs-build.sh
39
49
 
40
- FROM registry.ethernity.cloud:443/debuggingdelight/ethernity-cloud-sdk-registry/sconecuratedimages/crosscompilers as build
50
+ FROM registry.ethernity.cloud:443/debuggingdelight/ethernity-cloud-sdk-registry/sconecuratedimages/crosscompilers:alpine-scone6.0.7 as build
41
51
 
42
52
  COPY --from=release /binary-fs-dir /.
43
53
 
44
54
  RUN scone gcc ./binary_fs_blob.s ./libbinary_fs_template.a -shared -o /libbinary-fs.so
45
55
 
46
- #
47
- FROM registry.ethernity.cloud:443/debuggingdelight/ethernity-cloud-sdk-registry/ethernity/node:16.13.1-alpine3.15-scone5.8-production
56
+ FROM ${SCONE_NODE}
48
57
 
49
58
  COPY --from=build /libbinary-fs.so /lib/libbinary-fs.so
50
- #
51
-
52
- RUN apk update
53
-
54
- RUN apk add openssl
55
59
 
56
60
  RUN openssl genrsa -3 -out /enclave-key.pem 3072
57
61
 
@@ -64,24 +68,22 @@ ENV SCONE_HEAP=1024M
64
68
  ENV SCONE_STACK=4M
65
69
  ENV SCONE_ALLOW_DLOPEN=1
66
70
  ENV SCONE_EXTENSIONS_PATH=/lib/libbinary-fs.so
71
+ ENV SCONE_LOG=DEBUG
67
72
 
68
73
  # Rendered by build.mjs. Signs the EXECUTED binary (/usr/local/bin/node -- the
69
74
  # ENTRYPOINT and the run/publish compose command both run /usr/local/bin/node).
70
- # Mainnet adds --production (CAS/DCAP attestation); testnet omits it (non-CAS
71
- # self-sign). On testnet builds this line is a no-op comment.
75
+ # A CAS-provisioned securelock (mainnet, or a testnet with a SessionRegistry) is
76
+ # signed --production; a self-signing testnet one is signed debug.
72
77
  __SCONE_SIGN__
73
78
 
74
- # Record the SIGNED MRENCLAVE so publish (run.js) can assert the runtime enclave
75
- # measurement matches what was signed BEFORE registering the CAS session /
76
- # publishing. A mismatch means SCONE recomputed the enclave at load (params
77
- # drift) => debug re-sign => CAS rejects the DCAP quote on mainnet. Only produced
78
- # for --production (mainnet) signs; on testnet the file is absent and the check
79
- # is skipped. Capture to a file first: piping scone-signer into `head` kills it
79
+ # Record the SIGNED MRENCLAVE so publish (run.js) can assert, for a
80
+ # CAS-provisioned securelock, that the runtime enclave measurement matches what
81
+ # was signed BEFORE registering the CAS session. A mismatch means SCONE
82
+ # recomputed the enclave at load (params drift) => debug re-sign => the CAS
83
+ # rejects it. Capture to a file first: piping scone-signer into `head` kills it
80
84
  # with SIGPIPE (exit 141) under buildkit's pipefail shell.
81
85
  __SIGNED_MRENCLAVE__
82
86
 
83
87
  RUN rm -rf /enclave-key.pem
84
88
 
85
- #RUN scone cas attest scone-cas.cf 3061b9feb7fa67f3815336a085f629a13f04b0a1667c93b14ff35581dc8271e4 -GCS --only_for_testing-debug --only_for_testing-ignore-signer
86
- RUN ls /usr/local/bin
87
89
  ENTRYPOINT ["/usr/local/bin/node", "/etny-securelock/securelock.js"]
@@ -7,12 +7,13 @@ cat .env
7
7
  echo "####################"
8
8
 
9
9
  cat securelock.js.tmpl | sed s/"__ENCLAVE_NAME_SECURELOCK__"/"${ENCLAVE_NAME_SECURELOCK}"/g > securelock.js.tmp
10
- sed -i "s/__BUCKET_NAME__/${BUCKET_NAME}/g" securelock.js.tmp
11
- sed -i "s/__SMART_CONTRACT_ADDRESS__/${SMART_CONTRACT_ADDRESS}/g" securelock.js.tmp
12
- sed -i "s/__IMAGE_REGISTRY_ADDRESS__/${IMAGE_REGISTRY_ADDRESS}/g" securelock.js.tmp
13
- sed -i "s/__RPC_URL__/${RPC_URL}/g" securelock.js.tmp
14
- sed -i "s/__CHAIN_ID__/${CHAIN_ID}/g" securelock.js.tmp
15
- sed -i "s/__TRUSTED_ZONE_IMAGE__/${TRUSTED_ZONE_IMAGE}/g" securelock.js.tmp
10
+ # "|" delimits: the RPC URL contains "/".
11
+ sed -i "s|__ETNY_NETWORK_TYPE__|${NETWORK_TYPE}|g" securelock.js.tmp
12
+ sed -i "s|__ETNY_BUCKET__|${BUCKET_NAME}|g" securelock.js.tmp
13
+ sed -i "s|__ETNY_SMART_CONTRACT_ADDRESS__|${SMART_CONTRACT_ADDRESS}|g" securelock.js.tmp
14
+ sed -i "s|__ETNY_IMAGE_REGISTRY_ADDRESS__|${IMAGE_REGISTRY_ADDRESS}|g" securelock.js.tmp
15
+ sed -i "s|__ETNY_WEB3_PROVIDER__|${RPC_URL}|g" securelock.js.tmp
16
+ sed -i "s|__ETNY_CHAIN_ID__|${CHAIN_ID}|g" securelock.js.tmp
16
17
  # ethernity-cas ValidatorRegistry for CAS self-attestation. Deliberately NOT
17
18
  # overridable from the runtime environment (unlike the addresses above): the
18
19
  # session env comes from the CAS itself, and a rogue CAS must not get to
@@ -133,8 +133,11 @@ class EtnySecureLock {
133
133
  let host = parts[1];
134
134
  const port = parseInt(parts[3], 10);
135
135
  if (!Number.isInteger(port)) continue;
136
- // REST pairing convention: rest = 8081 + (enclave - 18765)
137
- const restPort = (port >= 18765 && port < 18965) ? 8081 + (port - 18765) : 8081;
136
+ // REST pairing convention: a CAS publishes its enclave port only,
137
+ // and its REST port sits at the same offset from the in-container
138
+ // pair 18765/8081 (19768 -> 9084).
139
+ const restPort = 8081 + (port - 18765);
140
+ if (restPort < 1 || restPort > 65535) continue;
138
141
  if (kind === 'onion3') {
139
142
  if (!host.endsWith('.onion')) host += '.onion';
140
143
  onion.push(`http://${host}:${restPort}`);
@@ -31,9 +31,9 @@ const writeEnv = (key, value) => {
31
31
  // Kept in sync with etny-{pynithy,nodenithy}/v3/networks.yaml (the authoritative
32
32
  // on-chain constants). Covers all supported networks for both dApp types.
33
33
  export const ECRunner = {
34
- // --- bloxberg ---
35
- 'etny-pynithy-testnet': ['0x02882F03097fE8cD31afbdFbB5D72a498B41112c', '0x15D73a742529C3fb11f3FA32EF7f0CC3870ACA31', 'https://bloxberg.ethernity.cloud', 8995],
36
- 'etny-nodenithy-testnet': ['0x02882F03097fE8cD31afbdFbB5D72a498B41112c', '0x15D73a742529C3fb11f3FA32EF7f0CC3870ACA31', 'https://bloxberg.ethernity.cloud', 8995],
34
+ // --- bloxberg (the testnet reads ECImageRegistryV2, mainnet the original) ---
35
+ 'etny-pynithy-testnet': ['0x02882F03097fE8cD31afbdFbB5D72a498B41112c', '0x99A84C624C028bdf0a855A1E9E3f2fcf7275B3D8', 'https://bloxberg.ethernity.cloud', 8995],
36
+ 'etny-nodenithy-testnet': ['0x02882F03097fE8cD31afbdFbB5D72a498B41112c', '0x99A84C624C028bdf0a855A1E9E3f2fcf7275B3D8', 'https://bloxberg.ethernity.cloud', 8995],
37
37
  'etny-pynithy': ['0x549A6E06BB2084100148D50F51CF77a3436C3Ae7', '0x15D73a742529C3fb11f3FA32EF7f0CC3870ACA31', 'https://bloxberg.ethernity.cloud', 8995],
38
38
  'etny-nodenithy': ['0x549A6E06BB2084100148D50F51CF77a3436C3Ae7', '0x15D73a742529C3fb11f3FA32EF7f0CC3870ACA31', 'https://bloxberg.ethernity.cloud', 8995],
39
39
  // --- polygon mainnet ---
@@ -50,7 +50,12 @@ export const ECRunner = {
50
50
  'ecld-nodenithy-ethereum-sepolia': ['0x29D3eC870565B6A1510232bd950A8Bc8336f0EB2', '0x55e0ad455Be85162b71a790f00Fc305680E3CE53', 'https://ethereum-sepolia-rpc.publicnode.com', 11155111],
51
51
  // --- litvm liteforge testnet (shares sepolia contracts; distinct chain/RPC) ---
52
52
  'ecld-pynithy-litvm-testnet': ['0x29D3eC870565B6A1510232bd950A8Bc8336f0EB2', '0x55e0ad455Be85162b71a790f00Fc305680E3CE53', 'https://liteforge.rpc.caldera.xyz/infra-partner-http', 4441],
53
- 'ecld-nodenithy-litvm-testnet': ['0x29D3eC870565B6A1510232bd950A8Bc8336f0EB2', '0x55e0ad455Be85162b71a790f00Fc305680E3CE53', 'https://liteforge.rpc.caldera.xyz/infra-partner-http', 4441]
53
+ 'ecld-nodenithy-litvm-testnet': ['0x29D3eC870565B6A1510232bd950A8Bc8336f0EB2', '0x55e0ad455Be85162b71a790f00Fc305680E3CE53', 'https://liteforge.rpc.caldera.xyz/infra-partner-http', 4441],
54
+ // --- the -unsafe networks: the contracts of the network each is named after ---
55
+ 'etny-pynithy-testnet-unsafe': ['0x02882F03097fE8cD31afbdFbB5D72a498B41112c', '0x99A84C624C028bdf0a855A1E9E3f2fcf7275B3D8', 'https://bloxberg.ethernity.cloud', 8995],
56
+ 'etny-nodenithy-testnet-unsafe': ['0x02882F03097fE8cD31afbdFbB5D72a498B41112c', '0x99A84C624C028bdf0a855A1E9E3f2fcf7275B3D8', 'https://bloxberg.ethernity.cloud', 8995],
57
+ 'ecld-pynithy-litvm-testnet-unsafe': ['0x29D3eC870565B6A1510232bd950A8Bc8336f0EB2', '0x55e0ad455Be85162b71a790f00Fc305680E3CE53', 'https://liteforge.rpc.caldera.xyz/infra-partner-http', 4441],
58
+ 'ecld-nodenithy-litvm-testnet-unsafe': ['0x29D3eC870565B6A1510232bd950A8Bc8336f0EB2', '0x55e0ad455Be85162b71a790f00Fc305680E3CE53', 'https://liteforge.rpc.caldera.xyz/infra-partner-http', 4441]
54
59
  };
55
60
 
56
61
  // ethernity-cas ValidatorRegistry per template, baked into the enclave so it
@@ -63,6 +68,19 @@ const require = createRequire(import.meta.url);
63
68
  const casConfig = require('../cas/config.js');
64
69
  export const VALIDATOR_REGISTRY = casConfig.VALIDATOR_REGISTRY;
65
70
 
71
+ // An -unsafe network runs an -unsafe trustedzone and nothing else, and an
72
+ // -unsafe trustedzone runs on no other network: the runner and the node refuse
73
+ // either mismatch, so the build does too.
74
+ const unsafe = casConfig.isUnsafeNetwork(process.env.BLOCKCHAIN_NETWORK);
75
+ if (unsafe !== String(process.env.TRUSTED_ZONE_IMAGE || '').endsWith('-unsafe')) {
76
+ console.error(`ERROR: TRUSTED_ZONE_IMAGE=${process.env.TRUSTED_ZONE_IMAGE} does not run on BLOCKCHAIN_NETWORK=${process.env.BLOCKCHAIN_NETWORK}.`);
77
+ console.error(unsafe
78
+ ? ' An -unsafe network runs only a trustedzone whose name ends in -unsafe.'
79
+ : ' A trustedzone whose name ends in -unsafe runs only on an -unsafe network.');
80
+ console.error(' Run ecld-init to choose the network again.');
81
+ process.exit(1);
82
+ }
83
+
66
84
  const runCommand = (command, canPass = false) => {
67
85
  if (shell.exec(command).code !== 0 && !canPass) {
68
86
  console.error(`Error executing command: ${command}`);
@@ -70,25 +88,22 @@ const runCommand = (command, canPass = false) => {
70
88
  }
71
89
  };
72
90
 
91
+ // Removes the containers this build and publish create, matched by exact name:
92
+ // `--filter name=` matches a substring, so name=las would also match the LAS of
93
+ // a CAS validator set on the same host.
94
+ const removeContainer = (name) => {
95
+ const ids = shell.exec(`docker ps -a -q --filter "name=^/${name}$"`, { silent: true }).stdout.trim();
96
+ if (ids) {
97
+ runCommand(`docker rm -f ${ids.split('\n').join(' ')}`);
98
+ }
99
+ };
100
+
73
101
  // Downloading dependencies
74
102
  shell.rm('-rf', './registry');
75
103
  const currentDir = process.cwd();
76
- // console.log(`current_dir: ${currentDir}`);
77
104
  const buildDir = path.join(currentDir, 'node_modules/@ethernity-cloud/sdk-js/nodenithy/build');
78
- // console.log(`build_dir: ${buildDir}`);
79
105
 
80
- const dockerPS = shell.exec('docker ps --filter name=registry -q', { silent: true }).stdout.trim();
81
- if (dockerPS) {
82
- runCommand(`docker stop ${dockerPS.split('\n').join(' ')}`);
83
- }
84
- const dockeri = shell.exec('docker ps --filter name=las -q', { silent: true }).stdout.trim();
85
- if (dockeri) {
86
- runCommand(`docker stop ${dockeri.split('\n').join(' ')}`);
87
- }
88
- const dockerRm = shell.exec('docker ps --filter name=registry -q', { silent: true }).stdout.trim();
89
- if (dockerRm) {
90
- runCommand(`docker rm ${dockerRm.split('\n').join(' ')} -f`);
91
- }
106
+ ['registry', 'las', 'etny-securelock', 'etny-trustedzone', 'etny-swift-stream'].forEach(removeContainer);
92
107
  const dockerImg = shell.exec('docker images --filter reference="*etny*" -q', { silent: true }).stdout.trim();
93
108
  if (dockerImg) {
94
109
  runCommand(`docker rmi ${dockerImg.split('\n').join(' ')} -f`);
@@ -97,7 +112,6 @@ const dockerImgReg = shell.exec('docker images --filter reference="*registry*" -
97
112
  if (dockerImgReg) {
98
113
  runCommand(`docker rmi ${dockerImgReg.split('\n').join(' ')} -f`);
99
114
  }
100
- runCommand(`docker rm registry -f`);
101
115
 
102
116
 
103
117
 
@@ -168,7 +182,7 @@ process.chdir(buildDir);
168
182
 
169
183
  let templateName = process.env.TRUSTED_ZONE_IMAGE || 'etny-nodenithy-testnet';
170
184
 
171
- const isMainnet = !templateName.includes('testnet');
185
+ const isMainnet = casConfig.isMainnetNetwork(process.env.BLOCKCHAIN_NETWORK);
172
186
 
173
187
  const ENCLAVE_NAME_TRUSTEDZONE = templateName;
174
188
 
@@ -178,10 +192,37 @@ runCommand('docker run -d --restart=always -p 5000:5000 --name registry registry
178
192
 
179
193
  // const CI_COMMIT_BRANCH = process.env.PROJECT_NAME;
180
194
  // aleXPRoj-securelock-v3-testnet-0.1.0...
181
- const ENCLAVE_NAME_SECURELOCK = `${process.env.PROJECT_NAME}-SECURELOCK-V3-${process.env.BLOCKCHAIN_NETWORK.split('_')[1].toLowerCase()}-${VERSION}`.replace(/\//g, '_').replace(/-/g, '_');
195
+ const ENCLAVE_NAME_SECURELOCK = `${process.env.PROJECT_NAME}-SECURELOCK-V3-${casConfig.sessionTag(process.env.BLOCKCHAIN_NETWORK)}-${VERSION}`.replace(/\//g, '_').replace(/-/g, '_');
182
196
  console.log(`ENCLAVE_NAME_SECURELOCK: ${ENCLAVE_NAME_SECURELOCK}`);
183
197
  writeEnv('ENCLAVE_NAME_SECURELOCK', ENCLAVE_NAME_SECURELOCK);
184
198
 
199
+ // The trustedzone is not built here: the etny-nodenithy CI builds, measures and
200
+ // registers it on-chain, and publishes that exact image to the ethernity registry
201
+ // under <image_name>/trustedzone:<network>, with image_name and network the keys
202
+ // of etny-nodenithy/v3/networks.yaml (image_name is TRUSTED_ZONE_IMAGE). Bundling
203
+ // anything else would pair the securelock with a trustedzone whose key does not
204
+ // match the on-chain cert, so a failed pull fails the build.
205
+ const trustedZoneNetByBlockchain = {
206
+ Bloxberg_Mainnet: 'bloxberg',
207
+ Bloxberg_Testnet: 'bloxberg_testnet',
208
+ Polygon_Mainnet: 'polygon',
209
+ Polygon_Amoy_Testnet: 'amoy',
210
+ IoTeX_Testnet: 'iotex_testnet',
211
+ Ethereum_Sepolia: 'ethereum_sepolia',
212
+ LitVM_LiteForge: 'litvm_liteforge',
213
+ Bloxberg_Testnet_Unsafe: 'bloxberg_testnet_unsafe',
214
+ LitVM_LiteForge_Unsafe: 'litvm_liteforge_unsafe',
215
+ };
216
+ const trustedZoneNet = trustedZoneNetByBlockchain[process.env.BLOCKCHAIN_NETWORK];
217
+ if (!trustedZoneNet) {
218
+ console.error(`ERROR: no published trustedzone for BLOCKCHAIN_NETWORK=${process.env.BLOCKCHAIN_NETWORK}`);
219
+ console.error(` known networks: ${Object.keys(trustedZoneNetByBlockchain).join(', ')}`);
220
+ process.exit(1);
221
+ }
222
+ const trustedZoneImage = `registry.ethernity.cloud:443/debuggingdelight/ethernity-cloud-sdk-registry/${templateName}/trustedzone:${trustedZoneNet}`;
223
+ console.log(`Pulling the published trustedzone: ${trustedZoneImage}`);
224
+ runCommand(`docker pull ${trustedZoneImage}`);
225
+
185
226
  console.log('Building etny-securelock');
186
227
  process.chdir('securelock');
187
228
 
@@ -217,7 +258,7 @@ const esrEnvBlock = ESR_ENABLED ? `ENV ESR_CONTRACT_ADDRESS=${ESR_CONTRACT_ADDRE
217
258
 
218
259
  // runCommand(`cat Dockerfile.tmpl | sed s/"__ENCLAVE_NAME_SECURELOCK__"/"${ENCLAVE_NAME_SECURELOCK}"/g > Dockerfile`);
219
260
  const dockerfileSecureTemplate = fs.readFileSync('Dockerfile.tmpl', 'utf8');
220
- 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(/__ETNY_VALIDATOR_REGISTRY_ADDRESS__/g, VALIDATOR_REGISTRY[templateName] || '').replace(/^__ESR_ENV__\n/m, esrEnvBlock ? `${esrEnvBlock}\n` : '');
261
+ let dockerfileSecureContent = dockerfileSecureTemplate.replace(/__ENCLAVE_NAME_SECURELOCK__/g, ENCLAVE_NAME_SECURELOCK).replace(/__NETWORK_TYPE__/g, isMainnet ? 'mainnet' : 'testnet').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(/__ETNY_VALIDATOR_REGISTRY_ADDRESS__/g, VALIDATOR_REGISTRY[templateName] || '').replace(/^__ESR_ENV__\n/m, esrEnvBlock ? `${esrEnvBlock}\n` : '');
221
262
 
222
263
  // Amount of enclave heap to allocate (SCONE_HEAP). Kept in sync with the
223
264
  // run/docker-compose securelock service; overridable via ECLD_MEMORY_TO_ALLOCATE.
@@ -247,74 +288,45 @@ const signedMrenclaveStep =
247
288
  ' | sed -E \'s/.*MRENCLAVE:[[:space:]]*//I\' | tr -d \'[:space:]\' > /signed_mrenclave.txt && \\\n' +
248
289
  ' echo "SIGNED_MRENCLAVE=$(cat /signed_mrenclave.txt)"';
249
290
 
250
- let imagesTag = process.env.BLOCKCHAIN_NETWORK.toLowerCase();
251
-
252
291
  // A CAS-provisioned securelock (mainnet, or a testnet with a SessionRegistry)
253
292
  // is signed --production: the CAS session admits production enclaves only,
254
- // and a debug-signed one is refused at attestation.
255
- if (casConfig.casProvisioned(templateName, isMainnet)) {
256
- dockerfileSecureContent = dockerfileSecureContent
257
- .replace('__SCONE_SIGN__', `RUN scone-signer sign ${signFlags} --production /usr/local/bin/node`)
258
- .replace('__SIGNED_MRENCLAVE__', signedMrenclaveStep);
259
- if (isMainnet) imagesTag = process.env.BLOCKCHAIN_NETWORK.split("_")[0].toLowerCase();
260
- } else {
261
- // Testnet: non-CAS self-sign path -- no --production sign and no signed
262
- // MRENCLAVE baking (the enclave self-signs from MR_ENCLAVE at runtime).
263
- dockerfileSecureContent = dockerfileSecureContent
264
- .replace('__SCONE_SIGN__', '# testnet: non-CAS self-sign (no --production sign at build time)')
265
- .replace('__SIGNED_MRENCLAVE__', '# testnet: no signed MRENCLAVE (self-signed from MR_ENCLAVE at runtime)');
266
- }
293
+ // and a debug-signed one is refused at attestation. A self-signing testnet
294
+ // securelock is signed debug with the same explicit params.
295
+ const cas = casConfig.casProvisioned(templateName, isMainnet);
296
+ dockerfileSecureContent = dockerfileSecureContent
297
+ .replace('__SCONE_SIGN__', `RUN scone-signer sign ${signFlags}${cas ? ' --production' : ''} /usr/local/bin/node`)
298
+ .replace('__SIGNED_MRENCLAVE__', signedMrenclaveStep);
267
299
 
268
300
  fs.writeFileSync('Dockerfile', dockerfileSecureContent);
269
301
 
270
302
 
271
303
 
272
304
 
273
- runCommand(`docker build --build-arg ENCLAVE_NAME_SECURELOCK=${ENCLAVE_NAME_SECURELOCK} -t etny-securelock:latest .`);
305
+ // The trustedzone image is also the securelock's SCONE node (Dockerfile.tmpl,
306
+ // SCONE_NODE).
307
+ runCommand(`docker build --build-arg SCONE_NODE=${trustedZoneImage} --build-arg ENCLAVE_NAME_SECURELOCK=${ENCLAVE_NAME_SECURELOCK} -t etny-securelock:latest .`);
274
308
  runCommand('docker tag etny-securelock localhost:5000/etny-securelock');
275
309
  runCommand('docker push localhost:5000/etny-securelock');
276
- // runCommand('docker save etny-securelock:latest -o etny-securelock.tar');
277
310
  process.chdir('..');
278
311
 
279
312
  console.log(`ENCLAVE_NAME_TRUSTEDZONE: ${ENCLAVE_NAME_TRUSTEDZONE}`);
280
313
  writeEnv('ENCLAVE_NAME_TRUSTEDZONE', ENCLAVE_NAME_TRUSTEDZONE);
281
314
 
282
- // The trustedzone is not built here: the etny-nodenithy CI builds, measures and
283
- // registers it on-chain, and publishes that exact image to the ethernity registry
284
- // under <image_name>/trustedzone:<network>, with image_name and network the keys
285
- // of etny-nodenithy/v3/networks.yaml (image_name is TRUSTED_ZONE_IMAGE). Bundling
286
- // anything else would pair the securelock with a trustedzone whose key does not
287
- // match the on-chain cert, so a failed pull fails the build.
288
- const trustedZoneNetByBlockchain = {
289
- Bloxberg_Mainnet: 'bloxberg',
290
- Bloxberg_Testnet: 'bloxberg_testnet',
291
- Polygon_Mainnet: 'polygon',
292
- Polygon_Amoy_Testnet: 'amoy',
293
- IoTeX_Testnet: 'iotex_testnet',
294
- Ethereum_Sepolia: 'ethereum_sepolia',
295
- LitVM_LiteForge: 'litvm_liteforge',
296
- };
297
- const trustedZoneNet = trustedZoneNetByBlockchain[process.env.BLOCKCHAIN_NETWORK];
298
- if (!trustedZoneNet) {
299
- console.error(`ERROR: no published trustedzone for BLOCKCHAIN_NETWORK=${process.env.BLOCKCHAIN_NETWORK}`);
300
- console.error(` known networks: ${Object.keys(trustedZoneNetByBlockchain).join(', ')}`);
301
- process.exit(1);
302
- }
303
- const trustedZoneImage = `registry.ethernity.cloud:443/debuggingdelight/ethernity-cloud-sdk-registry/${templateName}/trustedzone:${trustedZoneNet}`;
304
- console.log(`Pulling the published trustedzone: ${trustedZoneImage}`);
305
- runCommand(`docker pull ${trustedZoneImage}`);
306
315
  runCommand(`docker tag ${trustedZoneImage} localhost:5000/etny-trustedzone`);
307
316
  runCommand('docker push localhost:5000/etny-trustedzone');
308
317
 
309
318
 
310
- console.log('Building etny-las');
311
- process.chdir('las');
312
- // runCommand('docker build -t etny-las .');
313
- // runCommand('docker tag etny-las localhost:5000/etny-las');
314
- // runCommand('docker push localhost:5000/etny-las');
315
- runCommand(`docker pull registry.ethernity.cloud:443/debuggingdelight/ethernity-cloud-sdk-registry/ethernity/etny-las:${imagesTag}`);
316
- runCommand(`docker tag registry.ethernity.cloud:443/debuggingdelight/ethernity-cloud-sdk-registry/ethernity/etny-las:${imagesTag} localhost:5000/etny-las`);
317
- runCommand('docker push localhost:5000/etny-las');
319
+ // Every network but an -unsafe one runs a LAS beside the enclaves: the SCONE
320
+ // 6.0.7 LAS the trustedzones are built and attested with (etny-nodenithy
321
+ // v3/build/las). An -unsafe network's compose carries none, and its bundle
322
+ // none either.
323
+ if (!unsafe) {
324
+ const lasImage = 'registry.ethernity.cloud:443/debuggingdelight/ethernity-cloud-sdk-registry/sconecuratedimages/las:scone6.0.7';
325
+ console.log('Pulling etny-las');
326
+ runCommand(`docker pull ${lasImage}`);
327
+ runCommand(`docker tag ${lasImage} localhost:5000/etny-las`);
328
+ runCommand('docker push localhost:5000/etny-las');
329
+ }
318
330
 
319
331
 
320
332
  process.chdir(currentDir);
@@ -1,25 +1,30 @@
1
+ # The compose a node runs for this dApp; its SCONE_* values match
2
+ # docker-compose.yml.tmpl, which measured the securelock at publish. Tagged
3
+ # lines are kept, untagged, only where they apply (cas/config.js
4
+ # renderCompose): __CAS_ONLY__ serves CAS attestation, and __SAFE_ONLY__ is the
5
+ # LAS, which every network but an -unsafe one runs.
1
6
  version: '3.2'
2
7
  services:
3
- las:
4
- container_name: las
5
- privileged: true
6
- image: localhost:5000/etny-las
7
- entrypoint: "/las_entrypoint.sh"
8
- # -a 0.0.0.0: without it the LAS binds dual-stack (:::18766) and cannot
9
- # allocate the socket on a host booted with ipv6.disable=1, so it
10
- # crash-loops and every task on that node times out with no attestation.
11
- # The enclaves reach it over IPv4 either way.
12
- command: "/usr/local/bin/las -a 0.0.0.0"
13
- networks:
14
- - ethernity
15
- devices:
16
- - "/dev/sgx_enclave:/dev/sgx_enclave"
17
- restart: on-failure
18
- ports:
19
- - target: 18766
20
- published: 18766
21
- protocol: tcp
22
- mode: host
8
+ las: # __SAFE_ONLY__
9
+ container_name: las # __SAFE_ONLY__
10
+ privileged: true # __SAFE_ONLY__
11
+ image: localhost:5000/etny-las # __SAFE_ONLY__
12
+ entrypoint: "/las_entrypoint.sh" # __SAFE_ONLY__
13
+ # -a 0.0.0.0: without it the LAS binds dual-stack (:::18766) and cannot # __SAFE_ONLY__
14
+ # allocate the socket on a host booted with ipv6.disable=1, so it # __SAFE_ONLY__
15
+ # crash-loops and every task on that node times out with no attestation. # __SAFE_ONLY__
16
+ # The enclaves reach it over IPv4 either way. # __SAFE_ONLY__
17
+ command: "/usr/local/bin/las -a 0.0.0.0" # __SAFE_ONLY__
18
+ networks: # __SAFE_ONLY__
19
+ - ethernity # __SAFE_ONLY__
20
+ devices: # __SAFE_ONLY__
21
+ - "/dev/sgx_enclave:/dev/sgx_enclave" # __SAFE_ONLY__
22
+ restart: on-failure # __SAFE_ONLY__
23
+ ports: # __SAFE_ONLY__
24
+ - target: 18766 # __SAFE_ONLY__
25
+ published: 18766 # __SAFE_ONLY__
26
+ protocol: tcp # __SAFE_ONLY__
27
+ mode: host # __SAFE_ONLY__
23
28
 
24
29
  etny-securelock:
25
30
  container_name: etny-securelock
@@ -28,9 +33,9 @@ services:
28
33
  entrypoint: ""
29
34
  command: [ "/usr/local/bin/node", "/etny-securelock/securelock.js" ]
30
35
  environment:
31
- - SCONE_CAS_ADDR=scone-cas.cf
32
- - SCONE_LAS_ADDR=las
33
- - SCONE_CONFIG_ID=__ENCLAVE_NAME_SECURELOCK__/application
36
+ - SCONE_CAS_ADDR=scone-cas.cf # __CAS_ONLY__
37
+ - SCONE_LAS_ADDR=las # __CAS_ONLY__
38
+ - SCONE_CONFIG_ID=__ENCLAVE_NAME_SECURELOCK__/application # __CAS_ONLY__
34
39
  - SCONE_HEAP=1024M
35
40
  # Must match the --stack the securelock binary was signed with (build.mjs),
36
41
  # otherwise SCONE recomputes MRENCLAVE at load and re-signs as debug.
@@ -43,8 +48,8 @@ services:
43
48
  - ethernity
44
49
  devices:
45
50
  - "/dev/sgx_enclave:/dev/sgx_enclave"
46
- depends_on:
47
- - las
51
+ depends_on: # __SAFE_ONLY__
52
+ - las # __SAFE_ONLY__
48
53
 
49
54
  etny-trustedzone:
50
55
  container_name: etny-trustedzone
@@ -53,10 +58,10 @@ services:
53
58
  entrypoint: ""
54
59
  command: [ "/usr/local/bin/node", "/etny-trustedzone/trustedzone.js" ]
55
60
  environment:
56
- - SCONE_CAS_ADDR=scone-cas.cf
57
- - SCONE_LAS_ADDR=las
58
- - SCONE_CONFIG_ID=__ENCLAVE_NAME_TRUSTEDZONE__/application
59
- - SCONE_HEAP=256M
61
+ - SCONE_CAS_ADDR=scone-cas.cf # __CAS_ONLY__
62
+ - SCONE_LAS_ADDR=las # __CAS_ONLY__
63
+ - SCONE_CONFIG_ID=__ENCLAVE_NAME_TRUSTEDZONE__/application # __CAS_ONLY__
64
+ - SCONE_HEAP=__TRUSTEDZONE_HEAP__
60
65
  - SCONE_LOG=DEBUG
61
66
  - SCONE_ALLOW_DLOPEN=1
62
67
  - SCONE_EXTENSIONS_PATH=/lib/libbinary-fs.so
@@ -65,8 +70,8 @@ services:
65
70
  - ethernity
66
71
  devices:
67
72
  - "/dev/sgx_enclave:/dev/sgx_enclave"
68
- depends_on:
69
- - las
73
+ depends_on: # __SAFE_ONLY__
74
+ - las # __SAFE_ONLY__
70
75
  networks:
71
76
  ethernity:
72
77
  external: true