@cloudcommerce/cli 2.9.0 → 2.10.1

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloudcommerce/cli",
3
3
  "type": "module",
4
- "version": "2.9.0",
4
+ "version": "2.10.1",
5
5
  "description": "E-Com Plus Cloud Commerce CLI tools",
6
6
  "bin": {
7
7
  "cloudcommerce": "./bin/run.mjs"
@@ -11,6 +11,13 @@
11
11
  ".": "./lib/cli.js",
12
12
  "./create-auth": "./create-auth.js"
13
13
  },
14
+ "files": [
15
+ "/lib",
16
+ "/types",
17
+ "/*.{js,mjs,ts}",
18
+ "/ci/**/*.{sh,mjs}",
19
+ "/config/**/*.{json,rules,mjs,cjs}"
20
+ ],
14
21
  "repository": {
15
22
  "type": "git",
16
23
  "url": "git+https://github.com/ecomplus/cloud-commerce.git",
@@ -27,9 +34,9 @@
27
34
  "dotenv": "^16.4.5",
28
35
  "libsodium-wrappers": "^0.7.13",
29
36
  "md5": "^2.3.0",
30
- "typescript": "~5.2.2",
37
+ "typescript": "~5.4.3",
31
38
  "zx": "^7.2.3",
32
- "@cloudcommerce/api": "2.9.0"
39
+ "@cloudcommerce/api": "2.10.1"
33
40
  },
34
41
  "scripts": {
35
42
  "build": "bash ../../scripts/build-lib.sh"
@@ -1,5 +0,0 @@
1
-
2
-
3
- > @cloudcommerce/cli@2.8.8 build /home/leo/code/ecomplus/cloud-commerce/packages/cli
4
- > bash ../../scripts/build-lib.sh
5
-
package/CHANGELOG.md DELETED
@@ -1 +0,0 @@
1
- Please refer to GitHub [repository releases](https://github.com/ecomplus/cloud-commerce/releases) or monorepo unified [CHANGELOG.md](https://github.com/ecomplus/cloud-commerce/blob/main/CHANGELOG.md).
package/src/build.ts DELETED
@@ -1,56 +0,0 @@
1
- import { join as joinPath } from 'node:path';
2
- import { $, fs } from 'zx';
3
-
4
- const copyFunctionsConfig = async (isDev = false) => {
5
- const functionsDir = joinPath(process.cwd(), 'functions');
6
- if (isDev && !fs.existsSync(joinPath(functionsDir, '.env'))) {
7
- try {
8
- const { storeId } = JSON.parse(
9
- fs.readFileSync(joinPath(functionsDir, 'config.json'), 'utf8'),
10
- );
11
- await fs.writeFile(joinPath(functionsDir, '.env'), `ECOM_STORE_ID=${storeId}\n`);
12
- } catch {
13
- //
14
- }
15
- }
16
- const filesToCopy = ['.env', 'config.json', 'ssr/content/settings.json'];
17
- const dirents = await fs.readdir(functionsDir, { withFileTypes: true });
18
- /* eslint-disable no-await-in-loop */
19
- for (let i = 0; i < dirents.length; i++) {
20
- if (dirents[i].isDirectory() && dirents[i].name.charAt(0) !== '.') {
21
- const codebase = dirents[i].name;
22
- const codebaseDir = joinPath(functionsDir, codebase);
23
- const isSSR = codebase === 'ssr';
24
- await fs.ensureDir(joinPath(codebaseDir, 'content'));
25
- if (isDev && isSSR && !fs.existsSync(joinPath(functionsDir, 'ssr', 'node_modules'))) {
26
- await $`npm --prefix "functions/ssr" i`;
27
- }
28
- for (let ii = 0; ii < filesToCopy.length; ii++) {
29
- const fileToCopy = filesToCopy[ii];
30
- if (!isSSR || !fileToCopy.includes('ssr/')) {
31
- const srcPath = joinPath(functionsDir, fileToCopy);
32
- if (fs.existsSync(srcPath) && srcPath) {
33
- await fs.copy(
34
- srcPath,
35
- joinPath(codebaseDir, fileToCopy.replace('ssr/', '')),
36
- );
37
- }
38
- }
39
- }
40
- }
41
- }
42
- };
43
-
44
- const buildCodebase = async (codebase?: string) => {
45
- copyFunctionsConfig();
46
- if (codebase === 'ssr') {
47
- await $`npm --prefix "functions/ssr" run build 2>ssr-build-warns.log &&
48
- printf '\n--- // ---\n' && cat ssr-build-warns.log`;
49
- }
50
- };
51
-
52
- export default buildCodebase;
53
-
54
- export { buildCodebase, copyFunctionsConfig };
55
-
56
- export const prepareCodebases = copyFunctionsConfig;
package/src/cli.ts DELETED
@@ -1,228 +0,0 @@
1
- import { fileURLToPath } from 'node:url';
2
- import { join as joinPath } from 'node:path';
3
- import {
4
- $,
5
- argv,
6
- fs,
7
- echo,
8
- chalk,
9
- } from 'zx';
10
- import * as dotenv from 'dotenv';
11
- import Deepmerge from '@fastify/deepmerge';
12
- import login from './login';
13
- import build, { prepareCodebases } from './build';
14
- import { siginGcloudAndSetIAM, createServiceAccountKey } from './setup-gcloud';
15
- import createGhSecrets from './setup-gh';
16
-
17
- if (!process.env.FIREBASE_PROJECT_ID && !process.env.GOOGLE_APPLICATION_CREDENTIALS) {
18
- const pwd = process.cwd();
19
- dotenv.config();
20
- dotenv.config({ path: joinPath(pwd, 'functions/.env') });
21
- }
22
- const {
23
- FIREBASE_PROJECT_ID,
24
- GOOGLE_APPLICATION_CREDENTIALS,
25
- GITHUB_TOKEN,
26
- } = process.env;
27
-
28
- // https://github.com/google/zx/issues/124
29
- process.env.FORCE_COLOR = '3';
30
-
31
- const __dirname = fileURLToPath(new URL('.', import.meta.url));
32
- const pwd = process.cwd();
33
-
34
- let projectId = FIREBASE_PROJECT_ID;
35
- if (projectId) {
36
- if (!fs.existsSync(joinPath(pwd, '.firebaserc'))) {
37
- fs.writeFileSync(
38
- joinPath(pwd, '.firebaserc'),
39
- JSON.stringify({ projects: { default: projectId } }, null, 2),
40
- );
41
- }
42
- } else {
43
- if (GOOGLE_APPLICATION_CREDENTIALS) {
44
- try {
45
- const gac = fs.readJSONSync(joinPath(pwd, GOOGLE_APPLICATION_CREDENTIALS));
46
- projectId = gac.project_id;
47
- } catch (e) {
48
- //
49
- }
50
- }
51
- if (!projectId) {
52
- try {
53
- const firebaserc = fs.readJSONSync(joinPath(pwd, '.firebaserc'));
54
- projectId = firebaserc.projects.default;
55
- } catch (e) {
56
- projectId = 'ecom2-demo';
57
- }
58
- }
59
- }
60
-
61
- export default async () => {
62
- const baseConfigDir = joinPath(__dirname, '..', 'config');
63
- await fs.copy(baseConfigDir, pwd);
64
- const userConfigDir = joinPath(pwd, 'conf');
65
- if (fs.existsSync(userConfigDir) && fs.lstatSync(userConfigDir).isDirectory()) {
66
- await fs.copy(userConfigDir, pwd);
67
- const userFirebaseJsonPath = joinPath(userConfigDir, 'firebase.json');
68
- if (fs.existsSync(userFirebaseJsonPath)) {
69
- let userFirebaseConfig: Record<string, any> | undefined;
70
- try {
71
- userFirebaseConfig = JSON.parse(
72
- fs.readFileSync(userFirebaseJsonPath, 'utf8'),
73
- );
74
- } catch {
75
- //
76
- }
77
- if (userFirebaseConfig) {
78
- const deepmerge = Deepmerge();
79
- const baseFirebaseConfig = JSON.parse(
80
- fs.readFileSync(joinPath(baseConfigDir, 'firebase.json'), 'utf8'),
81
- );
82
- const mergedConfig = deepmerge(baseFirebaseConfig, userFirebaseConfig);
83
- fs.writeFileSync(
84
- joinPath(pwd, 'firebase.json'),
85
- JSON.stringify(mergedConfig, null, 2),
86
- );
87
- }
88
- }
89
- }
90
-
91
- const options: string[] = [];
92
- Object.keys(argv).forEach((key) => {
93
- if (key !== '_' && argv[key] !== false) {
94
- if (argv[key] !== true || (key !== 'codebase' && key !== 'only')) {
95
- options.push(`--${key}`, argv[key]);
96
- }
97
- }
98
- });
99
- const $firebase = (cmd: string) => {
100
- if (cmd === 'deploy' && !options.length) {
101
- return $`firebase --project=${projectId} ${cmd} --force`;
102
- }
103
- return $`firebase --project=${projectId} ${cmd} ${options}`;
104
- };
105
-
106
- if (argv._.includes('serve') || argv._.includes('preview')) {
107
- if (argv.build !== false) {
108
- await build(argv.codebase);
109
- }
110
- return $firebase('emulators:start').catch(async (err: any) => {
111
- await echo`
112
- Try killing open emulators with:
113
- ${chalk.bold('npx kill-port 4000 9099 5001 8080 5000 8085 9199 4400 4500')}
114
- `;
115
- if (err.stdout.includes('port taken')) {
116
- return process.exit(1);
117
- }
118
- throw err;
119
- });
120
- }
121
-
122
- if (argv._.find((cmd) => /^(\w+:)?shell$/.test(cmd))) {
123
- return $firebase('functions:shell');
124
- }
125
- if (argv._.find((cmd) => /^(\w+:)?logs?$/.test(cmd))) {
126
- return $firebase('functions:log');
127
- }
128
- if (argv._.includes('build')) {
129
- return build(argv.codebase);
130
- }
131
- if (argv._.includes('deploy')) {
132
- return $firebase('deploy');
133
- }
134
- if (argv._.includes('login')) {
135
- await $firebase('login');
136
- return login();
137
- }
138
-
139
- if (argv._.includes('setup')) {
140
- const { storeId, authenticationId, apiKey } = await login();
141
- await fs.writeFile(
142
- joinPath(pwd, 'functions', '.env'),
143
- `ECOM_AUTHENTICATION_ID=${authenticationId}
144
- ECOM_API_KEY=${apiKey}
145
- ECOM_STORE_ID=${storeId}
146
- `,
147
- );
148
-
149
- if (argv.deploy !== false) {
150
- await $firebase('deploy');
151
- }
152
- if (argv.commit !== false) {
153
- await fs.writeFile(
154
- joinPath(pwd, 'functions', 'config.json'),
155
- JSON.stringify({ storeId }, null, 2),
156
- );
157
-
158
- await build(argv.codebase);
159
- try {
160
- await $`git add .firebaserc functions/config.json`;
161
- await $`git commit -m "Setup store [skip ci]"`;
162
- await $`git push`;
163
- } catch (e) {
164
- //
165
- }
166
- }
167
- let serviceAccountJSON: string | null = null;
168
- if (argv.gcloud !== false) {
169
- try {
170
- await siginGcloudAndSetIAM(projectId as string, pwd);
171
- serviceAccountJSON = await createServiceAccountKey(projectId as string, pwd);
172
- } catch (e) {
173
- //
174
- }
175
- }
176
- let hasCreatedAllSecrets = false;
177
- if (GITHUB_TOKEN && argv.github !== false) {
178
- try {
179
- hasCreatedAllSecrets = await createGhSecrets(
180
- apiKey,
181
- authenticationId,
182
- serviceAccountJSON,
183
- GITHUB_TOKEN,
184
- );
185
- } catch (e) {
186
- //
187
- }
188
- }
189
-
190
- if (hasCreatedAllSecrets) {
191
- return echo`
192
- ****
193
-
194
- CloudCommerce setup completed successfully.
195
- Your store repository on GitHub is ready, the first deploy will automatically start with GH Actions.
196
-
197
- -- More info at https://github.com/ecomplus/store#getting-started
198
- `;
199
- }
200
- return echo`
201
- ****
202
-
203
- Finish by saving the following secrets to your GitHub repository:
204
-
205
- ${chalk.bold('ECOM_AUTHENTICATION_ID')} = ${chalk.bgMagenta(authenticationId)}
206
-
207
- ${chalk.bold('ECOM_API_KEY')} = ${chalk.bgMagenta(apiKey)}
208
-
209
- ${chalk.bold('FIREBASE_SERVICE_ACCOUNT')} = ${chalk.bgMagenta(serviceAccountJSON || '{YOUR_SERVICE_ACCOUNT_JSON}')}
210
-
211
- -- More info at https://github.com/ecomplus/store#getting-started
212
- `;
213
- }
214
-
215
- if (argv._.includes('prepare')) {
216
- return prepareCodebases();
217
- }
218
-
219
- if (argv._.includes('dev') || argv._.includes('start') || !argv._.length) {
220
- await prepareCodebases(true);
221
- const prefix = joinPath(pwd, 'functions/ssr');
222
- // https://docs.astro.build/en/reference/cli-reference/#astro-dev
223
- const host = typeof argv.host === 'string' ? argv.host : '';
224
- const port = typeof argv.port === 'string' || typeof argv.port === 'number' ? argv.port : '';
225
- return $`npm --prefix "${prefix}" run dev -- --host ${host} --port ${port}`;
226
- }
227
- return $`echo 'Hello from @cloudcommerce/cli'`;
228
- };
@@ -1,51 +0,0 @@
1
- import api from '@cloudcommerce/api';
2
-
3
- const defaultAgent = {
4
- name: 'Cloud Commerce default agent',
5
- email: 'cloudcommerce-noreply@e-com.plus',
6
- };
7
-
8
- export default async (storeId: number, accessToken: string) => {
9
- const apiConfig = {
10
- storeId,
11
- accessToken,
12
- };
13
- const { data } = await api.get('authentications', {
14
- ...apiConfig,
15
- params: {
16
- email: defaultAgent.email,
17
- limit: 1,
18
- },
19
- });
20
-
21
- let authenticationId = data.result[0]?._id;
22
- if (!authenticationId) {
23
- const { data: { _id } } = await api.post('authentications', {
24
- ...defaultAgent,
25
- username: `cloudcomm${Date.now()}`,
26
- permissions: {
27
- applications: ['all'],
28
- brands: ['all'],
29
- categories: ['all'],
30
- collections: ['all'],
31
- grids: ['all'],
32
- products: ['all'],
33
- customers: ['all'],
34
- carts: ['all'],
35
- orders: ['GET', 'POST', 'PATCH'],
36
- stores: ['GET', 'PATCH'],
37
- },
38
- }, apiConfig);
39
- authenticationId = _id;
40
- }
41
-
42
- const { data: apiKey } = await api.get(
43
- `authentications/${authenticationId}/api_key`,
44
- apiConfig,
45
- ) as { data: string };
46
- return {
47
- storeId,
48
- authenticationId,
49
- apiKey,
50
- };
51
- };
package/src/login.ts DELETED
@@ -1,45 +0,0 @@
1
- import * as readline from 'node:readline';
2
- import { question, echo } from 'zx';
3
- import md5 from 'md5';
4
- import api from '@cloudcommerce/api';
5
- import createAuth from './create-auth';
6
-
7
- export default async () => {
8
- await echo`-- Login with your E-Com Plus store admin account.
9
- (i) same credentials used to enter the dashboard (https://ecomplus.app/)
10
- `;
11
- const username = await question('E-Com Plus username: ');
12
- const passMd5 = await new Promise((resolve) => {
13
- const rl = readline.createInterface({
14
- input: process.stdin,
15
- output: process.stdout,
16
- }) as any;
17
- rl.stdoutMuted = true;
18
- rl.question('Password: ', (password) => {
19
- rl.close();
20
- rl.history = rl.history.slice(1);
21
- resolve(md5(password));
22
- });
23
- rl._writeToOutput = function _writeToOutput(stringToWrite) {
24
- if (rl.stdoutMuted) {
25
- rl.output.write('*');
26
- } else {
27
- rl.output.write(stringToWrite);
28
- }
29
- };
30
- });
31
-
32
- const { data: login } = await api.post('login', {
33
- username,
34
- pass_md5_hash: passMd5,
35
- });
36
- const storeId = login.store_ids[0];
37
-
38
- const {
39
- data: {
40
- access_token: accessToken,
41
- },
42
- } = await api.post('authenticate', login);
43
-
44
- return createAuth(storeId, accessToken);
45
- };
@@ -1,228 +0,0 @@
1
- import path from 'node:path';
2
- import {
3
- $,
4
- fs,
5
- question,
6
- echo,
7
- } from 'zx';
8
-
9
- let gcpAccessToken: string | undefined;
10
- const serviceAccountId = 'cloud-commerce-gh-actions';
11
- const getAccountEmail = (projectId: string) => {
12
- return `${serviceAccountId}@${projectId}.iam.gserviceaccount.com`;
13
- };
14
-
15
- const requestApi = async (
16
- projectId: string,
17
- options?: {
18
- baseURL?: string,
19
- url?: string,
20
- method: string,
21
- body?: string,
22
- },
23
- ) => {
24
- const body = options?.body;
25
- let url = options?.baseURL
26
- || `https://iam.googleapis.com/v1/projects/${projectId}/serviceAccounts`;
27
- url += options?.url || '';
28
- const data = await (await fetch(
29
- url,
30
- {
31
- method: options?.method || 'GET',
32
- headers: {
33
- Authorization: `Bearer ${gcpAccessToken}`,
34
- 'Content-Type': 'application/json; charset=utf-8',
35
- },
36
- body,
37
- },
38
- )).json() as any;
39
- const { error } = data;
40
- if (error) {
41
- let msgErr = 'Unexpected error in request';
42
- msgErr = error.message ? `Code: ${error.code} - ${error.message}` : msgErr;
43
- const err = new Error(msgErr);
44
- throw err;
45
- }
46
- return data;
47
- };
48
-
49
- const getGcpAccessToken = async () => {
50
- await echo`-- Get the Google Cloud account credentials:
51
- 1. Access https://shell.cloud.google.com/?fromcloudshell=true&show=terminal
52
- 2. Execute \`gcloud auth application-default print-access-token\` in Cloud Shell
53
- `;
54
- return question('Google Cloud access token: ');
55
- };
56
-
57
- const checkServiceAccountExists = async (projectId: string) => {
58
- let hasServiceAccount: boolean;
59
- try {
60
- if (!gcpAccessToken) {
61
- const { stderr } = await $`gcloud iam service-accounts describe ${getAccountEmail(projectId)}`;
62
- hasServiceAccount = !/not_?found/i.test(stderr);
63
- } else {
64
- // https://cloud.google.com/iam/docs/creating-managing-service-accounts?hl=pt-br#listing
65
- const { accounts: listAccounts } = await requestApi(projectId);
66
- const accountFound = listAccounts
67
- && listAccounts.find(({ email }) => email === getAccountEmail(projectId));
68
- hasServiceAccount = Boolean(accountFound);
69
- }
70
- } catch {
71
- return null;
72
- }
73
- return hasServiceAccount;
74
- };
75
-
76
- const siginGcloudAndSetIAM = async (projectId: string, pwd: string) => {
77
- let hasGcloud: boolean;
78
- try {
79
- hasGcloud = Boolean(await $`command -v gcloud`);
80
- } catch {
81
- hasGcloud = false;
82
- }
83
- if (hasGcloud) {
84
- if (/no credential/i.test((await $`gcloud auth list`).stderr)) {
85
- await $`gcloud auth login`;
86
- }
87
- await $`gcloud config set project ${projectId}`;
88
- } else {
89
- gcpAccessToken = await getGcpAccessToken();
90
- }
91
-
92
- const serviceAccount = await checkServiceAccountExists(projectId);
93
- if (!serviceAccount) {
94
- const description = 'A service account with permission to deploy Cloud Commerce'
95
- + ' from the GitHub repository to Firebase';
96
- const displayName = 'Cloud Commerce GH Actions';
97
- if (hasGcloud) {
98
- await $`gcloud iam service-accounts create ${serviceAccountId} \
99
- --description=${description} --display-name=${displayName}`;
100
- } else if (gcpAccessToken) {
101
- const body = JSON.stringify({
102
- accountId: serviceAccountId,
103
- serviceAccount: {
104
- description,
105
- displayName,
106
- },
107
- });
108
- await requestApi(projectId, { method: 'POST', body });
109
- }
110
- }
111
- await fs.ensureDir(path.join(pwd, '.cloudcommerce'));
112
- const pathPolicyIAM = path.join(pwd, '.cloudcommerce', 'policyIAM.json');
113
- let policyIAM: Record<string, any> = {};
114
- const version = 3; // most recent
115
- const baseURL = `https://cloudresourcemanager.googleapis.com/v1/projects/${projectId}`;
116
- if (hasGcloud) {
117
- await $`gcloud projects get-iam-policy ${projectId} --format json > ${pathPolicyIAM}`;
118
- policyIAM = fs.readJSONSync(pathPolicyIAM);
119
- } else if (gcpAccessToken) {
120
- // https://cloud.google.com/iam/docs/granting-changing-revoking-access?hl=pt-br#view-access
121
- // POST https://cloudresourcemanager.googleapis.com/API_VERSION/RESOURCE_TYPE/RESOURCE_ID:getIamPolicy
122
- policyIAM = await requestApi(
123
- projectId,
124
- {
125
- baseURL,
126
- url: ':getIamPolicy',
127
- method: 'POST',
128
- body: JSON.stringify({ options: { requestedPolicyVersion: version } }),
129
- },
130
- );
131
- }
132
-
133
- const roles = [
134
- 'roles/firebase.admin',
135
- 'roles/appengine.appAdmin',
136
- 'roles/appengine.appCreator',
137
- 'roles/artifactregistry.admin',
138
- 'roles/cloudfunctions.admin',
139
- 'roles/cloudscheduler.admin',
140
- 'roles/iam.serviceAccountUser',
141
- 'roles/run.viewer',
142
- 'roles/serviceusage.apiKeysViewer',
143
- 'roles/serviceusage.serviceUsageAdmin',
144
- ];
145
- let { bindings } = policyIAM;
146
- if (!bindings) {
147
- bindings = [];
148
- }
149
- let mustUpdatePolicy = false;
150
- roles.forEach((role) => {
151
- const roleFound = bindings.find((binding) => binding.role === role);
152
- const memberServiceAccount = `serviceAccount:${getAccountEmail(projectId)}`;
153
- if (!roleFound) {
154
- const newBinding: { [key: string]: any } = {
155
- members: [
156
- memberServiceAccount,
157
- ],
158
- role,
159
- };
160
- if (role === 'roles/serviceusage.serviceUsageAdmin') {
161
- const roleExpiration = Date.now() + 1000 * 60 * 60 * 12;
162
- newBinding.condition = {
163
- expression: `request.time < timestamp("${new Date(roleExpiration).toISOString()}")`,
164
- title: 'Enable APIs on first deploy',
165
- description: null,
166
- };
167
- }
168
- bindings.push(newBinding);
169
- mustUpdatePolicy = true;
170
- } else {
171
- const serviceAccountHavePermission = roleFound.members.find(
172
- (account: string) => account === memberServiceAccount,
173
- );
174
- if (!serviceAccountHavePermission) {
175
- roleFound.members.push(memberServiceAccount);
176
- mustUpdatePolicy = true;
177
- }
178
- }
179
- });
180
- if (mustUpdatePolicy) {
181
- if (hasGcloud) {
182
- fs.writeJSONSync(pathPolicyIAM, policyIAM);
183
- return $`gcloud projects set-iam-policy ${projectId} ${pathPolicyIAM}`;
184
- } if (gcpAccessToken) {
185
- Object.assign(policyIAM, { version, bindings });
186
- // POST https://cloudresourcemanager.googleapis.com/API_VERSION/RESOURCE_TYPE/RESOURCE_ID:setIamPolicy
187
- return requestApi(
188
- projectId,
189
- {
190
- baseURL,
191
- url: ':setIamPolicy',
192
- method: 'POST',
193
- body: JSON.stringify({ policy: policyIAM }),
194
- },
195
- );
196
- }
197
- }
198
- return null;
199
- };
200
-
201
- const createServiceAccountKey = async (projectId: string, pwd: string) => {
202
- try {
203
- const pathFileKey = path.join(pwd, '.cloudcommerce', 'serviceAccountKey.json');
204
- if (!gcpAccessToken) {
205
- await $`gcloud iam service-accounts keys create ${pathFileKey} \
206
- --iam-account=${getAccountEmail(projectId)}`;
207
- } else {
208
- const { privateKeyData } = await requestApi(
209
- projectId,
210
- {
211
- url: `/${getAccountEmail(projectId)}/keys`,
212
- method: 'POST',
213
- },
214
- );
215
- await $`echo '${privateKeyData}' | base64 --decode > ${pathFileKey}`;
216
- }
217
- return JSON.stringify(fs.readJSONSync(pathFileKey));
218
- } catch (e) {
219
- return null;
220
- }
221
- };
222
-
223
- export default siginGcloudAndSetIAM;
224
-
225
- export {
226
- siginGcloudAndSetIAM,
227
- createServiceAccountKey,
228
- };
package/src/setup-gh.ts DELETED
@@ -1,83 +0,0 @@
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;
package/tsconfig.json DELETED
@@ -1,6 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.json",
3
- "compilerOptions": {
4
- "sourceMap": false
5
- }
6
- }