@cloudcommerce/cli 0.0.58 → 0.0.61

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.
@@ -1,5 +1,5 @@
1
- @cloudcommerce/cli:build: cache hit, replaying output 1af9adb434178e30
2
- @cloudcommerce/cli:build: 
3
- @cloudcommerce/cli:build: > @cloudcommerce/cli@0.0.57 build /home/leo/code/ecomplus/cloud-commerce/packages/cli
4
- @cloudcommerce/cli:build: > sh ../../scripts/build-lib.sh
5
- @cloudcommerce/cli:build: 
1
+ @cloudcommerce/cli:build: cache hit, replaying output fd1e9d1edc462db0
2
+ @cloudcommerce/cli:build: 
3
+ @cloudcommerce/cli:build: > @cloudcommerce/cli@0.0.60 build /home/leo/code/ecomplus/cloud-commerce/packages/cli
4
+ @cloudcommerce/cli:build: > sh ../../scripts/build-lib.sh
5
+ @cloudcommerce/cli:build: 
@@ -40,15 +40,18 @@
40
40
  "rewrites": [
41
41
  {
42
42
  "source": "/api/modules/**",
43
- "function": "modules"
43
+ "function": "modules",
44
+ "region": "southamerica-east1"
44
45
  },
45
46
  {
46
47
  "source": "/api/passport/**",
47
- "function": "passport"
48
+ "function": "passport",
49
+ "region": "southamerica-east1"
48
50
  },
49
51
  {
50
52
  "source": "**/!(*(*.)js|*(*.)css|*(*.)ico|*(*.)png|*(*.)gif|*(*.)jpg|*(*.)jpeg|*(*.)webp|*(*.)avif|*(*.)svg|*(*.)woff|*(*.)woff2|*(*.)otf|*(*.)ttf|*(*.)eot)",
51
- "function": "ssr"
53
+ "function": "ssr",
54
+ "region": "southamerica-east1"
52
55
  }
53
56
  ],
54
57
  "cleanUrls": true
package/lib/index.js CHANGED
@@ -5,9 +5,10 @@ import {
5
5
  } from 'zx';
6
6
  import login from './login.js';
7
7
  import build from './build.js';
8
- import { siginGcloudAndSetIAM, createKeyServiceAccount } from './config-gcloud.js';
8
+ import { siginGcloudAndSetIAM, createServiceAccountKey } from './setup-gcloud.js';
9
+ import createGhSecrets from './setup-gh.js';
9
10
 
10
- const { FIREBASE_PROJECT_ID, GOOGLE_APPLICATION_CREDENTIALS } = process.env;
11
+ const { FIREBASE_PROJECT_ID, GOOGLE_APPLICATION_CREDENTIALS, GITHUB_TOKEN } = process.env;
11
12
  const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
12
13
  const pwd = process.cwd();
13
14
  let projectId = FIREBASE_PROJECT_ID;
@@ -29,7 +30,7 @@ if (projectId) {
29
30
  const firebaserc = fs.readJSONSync(path.join(pwd, '.firebaserc'));
30
31
  projectId = firebaserc.projects.default;
31
32
  } catch (e) {
32
- projectId = 'ecom2-001';
33
+ projectId = 'ecom2-002';
33
34
  }
34
35
  }
35
36
  }
@@ -102,11 +103,29 @@ ECOM_STORE_ID=${storeId}
102
103
  if (argv.gcloud !== false) {
103
104
  try {
104
105
  await siginGcloudAndSetIAM(projectId, pwd);
105
- serviceAccountJSON = await createKeyServiceAccount(projectId, pwd);
106
+ serviceAccountJSON = await createServiceAccountKey(projectId, pwd);
106
107
  } catch (e) {
107
108
  //
108
109
  }
109
110
  }
111
+ let hasCreatedAllSecrets = false;
112
+ if (GITHUB_TOKEN && argv.github !== false) {
113
+ try {
114
+ hasCreatedAllSecrets = await createGhSecrets(apiKey, authenticationId, serviceAccountJSON, GITHUB_TOKEN);
115
+ } catch (e) {
116
+ //
117
+ }
118
+ }
119
+ if (hasCreatedAllSecrets) {
120
+ return echo`
121
+ ****
122
+
123
+ CloudCommerce setup completed successfully.
124
+ Your store repository on GitHub is ready, the first deploy will automatically start with GH Actions.
125
+
126
+ -- More info at https://github.com/ecomplus/store#getting-started
127
+ `;
128
+ }
110
129
  return echo`
111
130
  ****
112
131
 
@@ -78,7 +78,7 @@ const siginGcloudAndSetIAM = async (projectId, pwd) => {
78
78
  }
79
79
  return null;
80
80
  };
81
- const createKeyServiceAccount = async (projectId, pwd) => {
81
+ const createServiceAccountKey = async (projectId, pwd) => {
82
82
  try {
83
83
  const pathFileKey = path.join(pwd, '.cloudcommerce', 'serviceAccountKey.json');
84
84
  await $`gcloud iam service-accounts keys create ${pathFileKey} \
@@ -91,4 +91,4 @@ const createKeyServiceAccount = async (projectId, pwd) => {
91
91
 
92
92
  export default siginGcloudAndSetIAM;
93
93
 
94
- export { siginGcloudAndSetIAM, createKeyServiceAccount };
94
+ export { siginGcloudAndSetIAM, createServiceAccountKey };
@@ -0,0 +1,59 @@
1
+ import { fetch, $ } from 'zx';
2
+ import libsodium from 'libsodium-wrappers';
3
+
4
+ const getRemoteRepo = async () => {
5
+ try {
6
+ return (await $`git config --get remote.origin.url`).stdout
7
+ .replace(/.*github.com[/:]/, '')
8
+ .replace('.git', '')
9
+ .replace('\n', '');
10
+ } catch (e) {
11
+ return null;
12
+ }
13
+ };
14
+ const createGhSecrets = async (ecomApiKey, ecomAuthentication, firebaseServiceAccount, ghToken, ghRepo) => {
15
+ const remoteRepo = ghRepo || await getRemoteRepo();
16
+ if (!remoteRepo) {
17
+ throw new Error("Can't define remote Git repository");
18
+ }
19
+ const baseUrl = `https://api.github.com/repos/${remoteRepo}/actions/secrets`;
20
+ const fetchGhSecrets = async (resource, body, method = 'GET') => {
21
+ const url = `${baseUrl}${resource}`;
22
+ const headers = {
23
+ Accept: 'application/vnd.github+json',
24
+ Authorization: `token ${ghToken}`,
25
+ };
26
+ return fetch(url, {
27
+ method,
28
+ headers,
29
+ body,
30
+ });
31
+ };
32
+ // https:// docs.github.com/pt/rest/actions/secrets#get-a-repository-public-key
33
+ const ghPublicKey = await (await fetchGhSecrets('/public-key')).json();
34
+ const ghKeyBuffer = Buffer.from(ghPublicKey.key, 'base64');
35
+ await libsodium.ready;
36
+ const createGhSecret = async (secretName, secretValue) => {
37
+ // https://docs.github.com/pt/rest/actions/secrets#example-encrypting-a-secret-using-nodejs
38
+ // Encryption example: https://github.com/github/tweetsodium
39
+ const encryptedBytes = libsodium.crypto_box_seal(Buffer.from(secretValue), ghKeyBuffer);
40
+ const body = {
41
+ encrypted_value: Buffer.from(encryptedBytes).toString('base64'),
42
+ key_id: ghPublicKey.key_id,
43
+ };
44
+ return fetchGhSecrets(`/${secretName}`, JSON.stringify(body), 'PUT');
45
+ };
46
+ try {
47
+ await createGhSecret('ECOM_API_KEY', ecomApiKey);
48
+ await createGhSecret('ECOM_AUTHENTICATION_ID', ecomAuthentication);
49
+ if (firebaseServiceAccount) {
50
+ await createGhSecret('FIREBASE_SERVICE_ACCOUNT', firebaseServiceAccount);
51
+ return true;
52
+ }
53
+ } catch (e) {
54
+ //
55
+ }
56
+ return false;
57
+ };
58
+
59
+ export default createGhSecrets;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloudcommerce/cli",
3
3
  "type": "module",
4
- "version": "0.0.58",
4
+ "version": "0.0.61",
5
5
  "description": "E-Com Plus Cloud Commerce CLI tools",
6
6
  "bin": {
7
7
  "cloudcommerce": "./bin/run.mjs"
@@ -23,7 +23,8 @@
23
23
  },
24
24
  "homepage": "https://github.com/ecomplus/cloud-commerce/tree/main/packages/cli#readme",
25
25
  "dependencies": {
26
- "@cloudcommerce/api": "0.0.58",
26
+ "@cloudcommerce/api": "0.0.61",
27
+ "libsodium-wrappers": "^0.7.10",
27
28
  "md5": "^2.3.0",
28
29
  "zx": "^7.0.8"
29
30
  },
package/src/index.ts CHANGED
@@ -9,11 +9,13 @@ import {
9
9
  } from 'zx';
10
10
  import login from './login';
11
11
  import build from './build';
12
- import { siginGcloudAndSetIAM, createKeyServiceAccount } from './config-gcloud';
12
+ import { siginGcloudAndSetIAM, createServiceAccountKey } from './setup-gcloud';
13
+ import createGhSecrets from './setup-gh';
13
14
 
14
15
  const {
15
16
  FIREBASE_PROJECT_ID,
16
17
  GOOGLE_APPLICATION_CREDENTIALS,
18
+ GITHUB_TOKEN,
17
19
  } = process.env;
18
20
 
19
21
  const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
@@ -41,7 +43,7 @@ if (projectId) {
41
43
  const firebaserc = fs.readJSONSync(path.join(pwd, '.firebaserc'));
42
44
  projectId = firebaserc.projects.default;
43
45
  } catch (e) {
44
- projectId = 'ecom2-001';
46
+ projectId = 'ecom2-002';
45
47
  }
46
48
  }
47
49
  }
@@ -103,6 +105,7 @@ ECOM_API_KEY=${apiKey}
103
105
  ECOM_STORE_ID=${storeId}
104
106
  `,
105
107
  );
108
+
106
109
  if (argv.deploy !== false) {
107
110
  await $firebase('deploy');
108
111
  }
@@ -111,6 +114,7 @@ ECOM_STORE_ID=${storeId}
111
114
  path.join(pwd, 'functions', 'config.json'),
112
115
  JSON.stringify({ storeId }, null, 2),
113
116
  );
117
+
114
118
  await build();
115
119
  try {
116
120
  await $`git add .firebaserc functions/config.json`;
@@ -124,12 +128,35 @@ ECOM_STORE_ID=${storeId}
124
128
  if (argv.gcloud !== false) {
125
129
  try {
126
130
  await siginGcloudAndSetIAM(projectId as string, pwd);
127
- serviceAccountJSON = await createKeyServiceAccount(projectId as string, pwd);
131
+ serviceAccountJSON = await createServiceAccountKey(projectId as string, pwd);
132
+ } catch (e) {
133
+ //
134
+ }
135
+ }
136
+ let hasCreatedAllSecrets = false;
137
+ if (GITHUB_TOKEN && argv.github !== false) {
138
+ try {
139
+ hasCreatedAllSecrets = await createGhSecrets(
140
+ apiKey,
141
+ authenticationId,
142
+ serviceAccountJSON,
143
+ GITHUB_TOKEN,
144
+ );
128
145
  } catch (e) {
129
146
  //
130
147
  }
131
148
  }
132
149
 
150
+ if (hasCreatedAllSecrets) {
151
+ return echo`
152
+ ****
153
+
154
+ CloudCommerce setup completed successfully.
155
+ Your store repository on GitHub is ready, the first deploy will automatically start with GH Actions.
156
+
157
+ -- More info at https://github.com/ecomplus/store#getting-started
158
+ `;
159
+ }
133
160
  return echo`
134
161
  ****
135
162
 
@@ -84,7 +84,7 @@ const siginGcloudAndSetIAM = async (projectId: string, pwd: string) => {
84
84
  return null;
85
85
  };
86
86
 
87
- const createKeyServiceAccount = async (projectId: string, pwd: string) => {
87
+ const createServiceAccountKey = async (projectId: string, pwd: string) => {
88
88
  try {
89
89
  const pathFileKey = path.join(pwd, '.cloudcommerce', 'serviceAccountKey.json');
90
90
  await $`gcloud iam service-accounts keys create ${pathFileKey} \
@@ -99,5 +99,5 @@ export default siginGcloudAndSetIAM;
99
99
 
100
100
  export {
101
101
  siginGcloudAndSetIAM,
102
- createKeyServiceAccount,
102
+ createServiceAccountKey,
103
103
  };
@@ -0,0 +1,83 @@
1
+ import { fetch, $ } from 'zx';
2
+ import libsodium from 'libsodium-wrappers';
3
+
4
+ const getRemoteRepo = async () => {
5
+ try {
6
+ return (await $`git config --get remote.origin.url`).stdout
7
+ .replace(/.*github.com[/:]/, '')
8
+ .replace('.git', '')
9
+ .replace('\n', '');
10
+ } catch (e) {
11
+ return null;
12
+ }
13
+ };
14
+
15
+ const createGhSecrets = async (
16
+ ecomApiKey: string,
17
+ ecomAuthentication: string,
18
+ firebaseServiceAccount: string | null,
19
+ ghToken: string,
20
+ ghRepo?: string,
21
+ ) => {
22
+ const remoteRepo = ghRepo || await getRemoteRepo();
23
+ if (!remoteRepo) {
24
+ throw new Error("Can't define remote Git repository");
25
+ }
26
+ const baseUrl = `https://api.github.com/repos/${remoteRepo}/actions/secrets`;
27
+
28
+ const fetchGhSecrets = async (
29
+ resource: string,
30
+ body?: string,
31
+ method: string = 'GET',
32
+ ) => {
33
+ const url = `${baseUrl}${resource}`;
34
+ const headers = {
35
+ Accept: 'application/vnd.github+json',
36
+ Authorization: `token ${ghToken}`,
37
+ };
38
+ return fetch(url, {
39
+ method,
40
+ headers,
41
+ body,
42
+ });
43
+ };
44
+
45
+ // https:// docs.github.com/pt/rest/actions/secrets#get-a-repository-public-key
46
+ const ghPublicKey = await (await fetchGhSecrets('/public-key')).json() as {
47
+ key_id: string,
48
+ key: string,
49
+ };
50
+ const ghKeyBuffer = Buffer.from(ghPublicKey.key, 'base64');
51
+ await libsodium.ready;
52
+
53
+ const createGhSecret = async (
54
+ secretName: string,
55
+ secretValue: string,
56
+ ) => {
57
+ // https://docs.github.com/pt/rest/actions/secrets#example-encrypting-a-secret-using-nodejs
58
+ // Encryption example: https://github.com/github/tweetsodium
59
+ const encryptedBytes = libsodium.crypto_box_seal(
60
+ Buffer.from(secretValue),
61
+ ghKeyBuffer,
62
+ );
63
+ const body = {
64
+ encrypted_value: Buffer.from(encryptedBytes).toString('base64'),
65
+ key_id: ghPublicKey.key_id,
66
+ };
67
+ return fetchGhSecrets(`/${secretName}`, JSON.stringify(body), 'PUT');
68
+ };
69
+
70
+ try {
71
+ await createGhSecret('ECOM_API_KEY', ecomApiKey);
72
+ await createGhSecret('ECOM_AUTHENTICATION_ID', ecomAuthentication);
73
+ if (firebaseServiceAccount) {
74
+ await createGhSecret('FIREBASE_SERVICE_ACCOUNT', firebaseServiceAccount);
75
+ return true;
76
+ }
77
+ } catch (e) {
78
+ //
79
+ }
80
+ return false;
81
+ };
82
+
83
+ export default createGhSecrets;