@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.
- package/README.md +44 -6
- package/cas/config.js +61 -3
- package/info.js +333 -324
- package/init.js +20 -4
- package/nodenithy/build/securelock/Dockerfile.tmpl +34 -32
- package/nodenithy/build/securelock/scripts/binary-fs-build.sh +7 -6
- package/nodenithy/build/securelock/src/securelock.js.tmpl +5 -2
- package/nodenithy/build.mjs +83 -71
- package/nodenithy/run/docker-compose-final.yml.tmpl +36 -31
- package/nodenithy/run/docker-compose.yml.tmpl +34 -45
- package/nodenithy/run/image_registry.js +396 -380
- package/nodenithy/run.js +42 -28
- package/package.json +5 -3
- package/publish.js +4 -2
- package/pynithy/build/securelock/Dockerfile.base.tpl +13 -0
- package/pynithy/build/securelock/Dockerfile.tpl +131 -0
- package/pynithy/build/securelock/scripts/binary-fs-build.sh +25 -34
- package/pynithy/build/securelock/scripts/pyfreeze.sh +32 -0
- package/pynithy/build/securelock/src/{pox.abi → abi/etnyImplementationV2.abi} +1489 -1489
- package/pynithy/build/securelock/src/abi/image_registry.abi +1 -0
- package/pynithy/build/securelock/src/ecld_state.py +906 -0
- package/pynithy/build/securelock/src/esr.abi +1 -0
- package/pynithy/build/securelock/src/esr_local.py +267 -0
- package/pynithy/build/securelock/src/esr_wallet.py +150 -0
- package/pynithy/build/securelock/src/etny_crypto.py +208 -167
- package/pynithy/build/securelock/src/etny_exec.py +385 -79
- package/pynithy/build/securelock/src/etny_exec_flask.py +535 -0
- package/pynithy/build/securelock/src/etny_exec_serv.py +353 -0
- package/pynithy/build/securelock/src/etny_session_exec.py +245 -0
- package/pynithy/build/securelock/src/get_sgx_report.so +0 -0
- package/pynithy/build/securelock/src/image_registry.abi +1 -1
- package/pynithy/build/securelock/src/key_generation.py +17 -17
- package/pynithy/build/securelock/src/local_api.py +189 -0
- package/pynithy/build/securelock/src/models.py +200 -176
- package/pynithy/build/securelock/src/securelock.py.tmpl +1037 -727
- package/pynithy/build/securelock/src/swift_stream_service.py +206 -186
- package/pynithy/build.mjs +142 -92
- package/pynithy/run/docker-compose-final.yml.tmpl +58 -51
- package/pynithy/run/docker-compose.yml.tmpl +62 -48
- package/pynithy/run/etny-securelock-test.yaml.tpl +4 -1
- package/pynithy/run/image_registry.js +396 -380
- package/pynithy/run.js +44 -28
- package/pynithy/src/serverless/Dockerfile.serverless +8 -0
- package/pynithy/src/serverless/requirements.txt +6 -0
- package/run.js +69 -28
- package/nodenithy/build/las/Dockerfile +0 -5
- package/pynithy/build/docker-compose.yml +0 -70
- package/pynithy/build/las/Dockerfile +0 -11
- package/pynithy/build/las/src/etny_entrypoint.sh +0 -6
- package/pynithy/build/las/src/las_entrypoint.sh +0 -26
- package/pynithy/build/scripts/binary-fs-build.sh +0 -28
- 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 ${
|
|
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
|
-
|
|
202
|
-
|
|
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",
|
|
366
|
+
writeEnv("BLOCKCHAIN_NETWORK", network);
|
|
351
367
|
writeEnv("IPFS_ENDPOINT", customUrl);
|
|
352
368
|
console.log();
|
|
353
369
|
await configureEsr();
|
|
@@ -1,20 +1,35 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
4
|
-
|
|
5
|
-
RUN
|
|
13
|
+
COPY ./src /etny-securelock/
|
|
14
|
+
WORKDIR /etny-securelock
|
|
15
|
+
RUN npm install
|
|
6
16
|
|
|
7
|
-
|
|
17
|
+
FROM ${SCONE_NODE} AS release
|
|
8
18
|
|
|
9
|
-
|
|
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
|
|
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
|
-
#
|
|
71
|
-
# self-
|
|
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
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
# drift) => debug re-sign =>
|
|
78
|
-
#
|
|
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
|
-
|
|
11
|
-
sed -i "s
|
|
12
|
-
sed -i "s
|
|
13
|
-
sed -i "s
|
|
14
|
-
sed -i "s
|
|
15
|
-
sed -i "s
|
|
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:
|
|
137
|
-
|
|
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}`);
|
package/nodenithy/build.mjs
CHANGED
|
@@ -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', '
|
|
36
|
-
'etny-nodenithy-testnet': ['0x02882F03097fE8cD31afbdFbB5D72a498B41112c', '
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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(/
|
|
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
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
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
|
-
|
|
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
|
-
|
|
311
|
-
|
|
312
|
-
//
|
|
313
|
-
//
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
runCommand(
|
|
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=
|
|
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
|