@ethernity-cloud/sdk-js 1.7.7 → 1.7.8

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 CHANGED
@@ -50,7 +50,8 @@ The sdk has been tested on the following operating systems:
50
50
  for the compose and the certificate harvest, takes the trustedzone
51
51
  session name from the ImageRegistry, and links the session to the
52
52
  published image. `ecld-build` signs the securelock `--production`.
53
- Harvesting the certificate needs SGX.
53
+ The certificate is harvested on an SGX host or, without one, extracted
54
+ by publickey.ethernity.cloud (see "How the image reaches the network").
54
55
  - Testnet Unsafe - the unsafe network beside the testnet (see below).
55
56
  - Mainnet - to be provided during the following updates
56
57
  - LitVM:
package/localKubo.js CHANGED
@@ -46,6 +46,14 @@ function freePort() {
46
46
  });
47
47
  }
48
48
 
49
+ // The host port in the first line of `docker port <container> 5001/tcp`
50
+ // (`127.0.0.1:60823`), or null when there is none.
51
+ function apiPortIn(dockerPortOutput) {
52
+ const first = String(dockerPortOutput || '').trim().split('\n')[0] || '';
53
+ const match = /:(\d+)$/.exec(first.trim());
54
+ return match ? Number(match[1]) : null;
55
+ }
56
+
49
57
  // Whether the configured endpoint is one of the application's own; the public
50
58
  // API and an empty setting both mean "run a Kubo for this publish".
51
59
  function ownEndpoint(endpoint) {
@@ -62,6 +70,10 @@ class LocalKubo {
62
70
  this.container = `ecld-kubo-${String(name || 'publish').replace(/[^A-Za-z0-9_.-]/g, '-')}`;
63
71
  this.peers = (process.env.ECLD_IPFS_PEERS || BOOTNODE_MULTIADDR).split(',').map((p) => p.trim()).filter(Boolean);
64
72
  this.apiUrl = null;
73
+ // True while a registered image has this Kubo as its source: from the
74
+ // image's registration on chain until its certificate is on chain. A
75
+ // publish that ends in between leaves the Kubo running (release).
76
+ this.serving = false;
65
77
  }
66
78
 
67
79
  async api(command, params, timeout) {
@@ -69,21 +81,40 @@ class LocalKubo {
69
81
  return response.data;
70
82
  }
71
83
 
72
- // Start the container and wait for its API; peer it with the bootnode.
73
- // Throws when docker cannot run it or the API does not come up in time.
74
- async start() {
75
- const apiPort = await freePort();
76
- this.apiUrl = `http://127.0.0.1:${apiPort}`;
77
- try { execFileSync('docker', ['rm', '-f', this.container], { stdio: 'ignore' }); } catch (e) { /* not running */ }
78
- const args = ['run', '-d', '--name', this.container, '-p', `127.0.0.1:${apiPort}:5001`];
79
- if (await portFree(SWARM_PORT)) {
80
- args.push('-p', `${SWARM_PORT}:4001`, '-p', `${SWARM_PORT}:4001/udp`);
81
- }
82
- args.push(KUBO_IMAGE, 'daemon', '--init', '--migrate=true');
84
+ // The API port of the container a previous publish of this project left
85
+ // running (release), or null when none runs.
86
+ keptApiPort() {
83
87
  try {
84
- execFileSync('docker', args, { stdio: ['ignore', 'pipe', 'pipe'] });
88
+ return apiPortIn(execFileSync('docker', ['port', this.container, '5001/tcp'], { stdio: ['ignore', 'pipe', 'ignore'] }));
85
89
  } catch (e) {
86
- throw new Error(`docker could not start ${KUBO_IMAGE}: ${String(e.stderr || e.message).trim()}`);
90
+ return null;
91
+ }
92
+ }
93
+
94
+ // Start the container and wait for its API, or take over the one a
95
+ // previous publish of this project left serving its registered image,
96
+ // whose peer id that image's registry entry names; peer it with the
97
+ // bootnode. Throws when docker cannot run it or the API does not come up
98
+ // in time.
99
+ async start() {
100
+ const kept = this.keptApiPort();
101
+ if (kept !== null) {
102
+ this.apiUrl = `http://127.0.0.1:${kept}`;
103
+ console.log(`\t✔ IPFS node of the previous publish kept: ${this.container}`);
104
+ } else {
105
+ const apiPort = await freePort();
106
+ this.apiUrl = `http://127.0.0.1:${apiPort}`;
107
+ try { execFileSync('docker', ['rm', '-f', this.container], { stdio: 'ignore' }); } catch (e) { /* not running */ }
108
+ const args = ['run', '-d', '--name', this.container, '-p', `127.0.0.1:${apiPort}:5001`];
109
+ if (await portFree(SWARM_PORT)) {
110
+ args.push('-p', `${SWARM_PORT}:4001`, '-p', `${SWARM_PORT}:4001/udp`);
111
+ }
112
+ args.push(KUBO_IMAGE, 'daemon', '--init', '--migrate=true');
113
+ try {
114
+ execFileSync('docker', args, { stdio: ['ignore', 'pipe', 'pipe'] });
115
+ } catch (e) {
116
+ throw new Error(`docker could not start ${KUBO_IMAGE}: ${String(e.stderr || e.message).trim()}`);
117
+ }
87
118
  }
88
119
  const deadline = Date.now() + API_READY_MS;
89
120
  for (;;) {
@@ -155,6 +186,20 @@ class LocalKubo {
155
186
  stop() {
156
187
  try { execFileSync('docker', ['rm', '-f', this.container], { stdio: 'ignore' }); } catch (e) { /* already gone */ }
157
188
  }
189
+
190
+ // End the publish's use of the Kubo: stop it, unless it is the source of
191
+ // a registered image whose certificate is not on chain yet, which it keeps
192
+ // serving to the extraction service and the bootnode's mirror; the next
193
+ // publish of the project takes it over, `docker rm -f` stops it.
194
+ release() {
195
+ if (!this.serving) {
196
+ this.stop();
197
+ return;
198
+ }
199
+ console.log(`\t⚠ The registered image stays available from this publish's IPFS node, the docker`);
200
+ console.log(`\t container ${this.container}, for the extraction service and the bootnode.`);
201
+ console.log(`\t Publish again to retry; \`docker rm -f ${this.container}\` stops it.`);
202
+ }
158
203
  }
159
204
 
160
- module.exports = { LocalKubo, ownEndpoint, PUBLIC_IPFS_HOST };
205
+ module.exports = { LocalKubo, ownEndpoint, apiPortIn, PUBLIC_IPFS_HOST };
package/nodenithy/run.js CHANGED
@@ -137,7 +137,7 @@ const main = async () => {
137
137
  }
138
138
  ipfsApi = localKubo.apiUrl;
139
139
  console.log(`\t✔ IPFS node for this publish: ${ipfsApi}`);
140
- process.on('exit', () => localKubo.stop());
140
+ process.on('exit', () => localKubo.release());
141
141
  }
142
142
 
143
143
  // The CIDs uploadToIpfs gives, from the same add calls with only-hash: the
@@ -580,6 +580,9 @@ const main = async () => {
580
580
  hashForIpfs();
581
581
  if (localKubo) ipfsPeer = await localKubo.peerMultiaddr();
582
582
  execSync(`node ${runDir}/image_registry.js "${process.env.BLOCKCHAIN_NETWORK}" "${securelock}" "v3" "registerImage"`, { stdio: "inherit", env: { ...process.env, PROJECT_NAME: securelock, IPFS_PEER: ipfsPeer } });
583
+ // From here the registered image's source is this Kubo, until its
584
+ // certificate is on chain.
585
+ if (localKubo) localKubo.serving = true;
583
586
  }
584
587
  uploadToIpfs();
585
588
  const registryEnv = { ...process.env, PROJECT_NAME: securelock, IPFS_PEER: ipfsPeer };
@@ -711,6 +714,7 @@ const main = async () => {
711
714
  process.chdir(currentDir);
712
715
  console.log(`Registering the certificate of SECURELOCK ${securelock} in the IMAGE REGISTRY smart contract...`);
713
716
  execSync(`node ${runDir}/image_registry.js "${process.env.BLOCKCHAIN_NETWORK}" "${securelock}" "v3" "setImageCert"`, { stdio: "inherit", env: registryEnv });
717
+ if (localKubo) localKubo.serving = false;
714
718
  } else {
715
719
  // A V1 registry gets the tree that carries the certificate files,
716
720
  // uploaded again, with the certificate, in one addImage call.
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "@ethernity-cloud/sdk-js",
3
- "version": "1.7.7",
3
+ "version": "1.7.8",
4
4
  "description": "A package to run ethernity cloud build scripts",
5
5
  "scripts": {
6
+ "test": "node --test \"test/**/*.test.js\"",
6
7
  "ecld-build": "cross-env node ./node_modules/@ethernity-cloud/sdk-js/build.js",
7
8
  "ecld-publish": "cross-env node ./node_modules/@ethernity-cloud/sdk-js/publish.js",
8
9
  "ecld-init": "cross-env node ./node_modules/@ethernity-cloud/sdk-js/init.js",
package/pynithy/run.js CHANGED
@@ -138,7 +138,7 @@ const main = async () => {
138
138
  }
139
139
  ipfsApi = localKubo.apiUrl;
140
140
  console.log(`\t✔ IPFS node for this publish: ${ipfsApi}`);
141
- process.on('exit', () => localKubo.stop());
141
+ process.on('exit', () => localKubo.release());
142
142
  }
143
143
 
144
144
  // The CIDs uploadToIpfs gives, from the same add calls with only-hash: the
@@ -579,6 +579,9 @@ const main = async () => {
579
579
  hashForIpfs();
580
580
  if (localKubo) ipfsPeer = await localKubo.peerMultiaddr();
581
581
  execSync(`node ${runDir}/image_registry.js "${process.env.BLOCKCHAIN_NETWORK}" "${securelock}" "v3" "registerImage"`, { stdio: "inherit", env: { ...process.env, PROJECT_NAME: securelock, IPFS_PEER: ipfsPeer } });
582
+ // From here the registered image's source is this Kubo, until its
583
+ // certificate is on chain.
584
+ if (localKubo) localKubo.serving = true;
582
585
  }
583
586
  uploadToIpfs();
584
587
  const registryEnv = { ...process.env, PROJECT_NAME: securelock, IPFS_PEER: ipfsPeer };
@@ -688,6 +691,7 @@ const main = async () => {
688
691
  process.chdir(currentDir);
689
692
  console.log(`Registering the certificate of SECURELOCK ${securelock} in the IMAGE REGISTRY smart contract...`);
690
693
  execSync(`node ${runDir}/image_registry.js "${process.env.BLOCKCHAIN_NETWORK}" "${securelock}" "v3" "setImageCert"`, { stdio: "inherit", env: registryEnv });
694
+ if (localKubo) localKubo.serving = false;
691
695
  } else {
692
696
  // A V1 registry gets the tree that carries the certificate files,
693
697
  // uploaded again, with the certificate, in one addImage call.