@fishawack/lab-env 3.2.0 → 4.0.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/CHANGELOG.md +6 -0
- package/_Test/email.js +12 -0
- package/_Test/utilities.js +40 -0
- package/cli.js +0 -3
- package/commands/create/cmds/deprovision.js +3 -3
- package/commands/create/cmds/key.js +23 -3
- package/commands/create/cmds/provision.js +1 -1
- package/commands/create/libs/utilities.js +18 -0
- package/commands/create/services/aws/index.js +4 -2
- package/commands/create/services/email.js +44 -0
- package/globals.js +16 -11
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
## Changelog
|
|
2
2
|
|
|
3
|
+
### 4.0.0 (2022-09-12)
|
|
4
|
+
* [Feature] Added new s3Safe repo to enforce safe s3 service names
|
|
5
|
+
* [Feature] Added newly setup AWS accounts to the client prompts on `fw provision`
|
|
6
|
+
* [Feature] key command can now send credentials via email
|
|
7
|
+
* [Bug] deprov command now uses repo safe
|
|
8
|
+
|
|
3
9
|
### 3.2.0 (2022-09-12)
|
|
4
10
|
* [Feature] Added newly setup AWS accounts to the client prompts on `fw provision`
|
|
5
11
|
* [Change] Clients now listed in alphabetical order
|
package/_Test/email.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const expect = require('chai').expect;
|
|
4
|
+
const email = require("../commands/create/services/email.js");
|
|
5
|
+
|
|
6
|
+
describe('email', async () => {
|
|
7
|
+
it('Should send email', async () => {
|
|
8
|
+
let info = await email.send('mike.mellor@fishawack.com', 'New AWS Keys', 'hello', null, true);
|
|
9
|
+
|
|
10
|
+
expect(info.response).to.contain('250');
|
|
11
|
+
});
|
|
12
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const expect = require('chai').expect;
|
|
4
|
+
const { s3Safe } = require("../commands/create/libs/utilities.js");
|
|
5
|
+
|
|
6
|
+
describe('utilities', async () => {
|
|
7
|
+
describe('s3Safe', () => {
|
|
8
|
+
it('Should enforce service name to be at least 3 chars', async () => {
|
|
9
|
+
expect(s3Safe('a').length).to.be.greaterThanOrEqual(3);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('Should limit service name to 63 chars', async () => {
|
|
13
|
+
expect(s3Safe('a'.repeat(100)).length).to.be.lessThanOrEqual(63);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('Should remove any uppercase chars', async () => {
|
|
17
|
+
expect(/^[A-Z]*$/.test(s3Safe('TEST'))).to.be.false;
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('Should convert . to -', async () => {
|
|
21
|
+
expect(s3Safe('...').match(/\./g)).to.be.null;
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('Should convert _ to -', async () => {
|
|
25
|
+
expect(s3Safe('___').match(/\_/g)).to.be.null;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('Should start with a number or char', async () => {
|
|
29
|
+
expect(/[a-z0-9]/i.test(s3Safe('___').charAt(0))).to.be.true;
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('Should end with a number or char', async () => {
|
|
33
|
+
expect(/[a-z0-9]/i.test(s3Safe('___').charAt(s3Safe('___').length - 1))).to.be.true;
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('Should remove any special chars', async () => {
|
|
37
|
+
expect(s3Safe('!@#$%^&*()=_+;,./<>?~`|').match(/[\!\@\#\$\%\^\&\*\(\)\=\_\+\;\,\.\/\<\>\?\~\`\|]/g)).to.be.null;
|
|
38
|
+
});
|
|
39
|
+
})
|
|
40
|
+
});
|
package/cli.js
CHANGED
|
@@ -11,9 +11,6 @@ const { hideBin } = require('yargs/helpers');
|
|
|
11
11
|
|
|
12
12
|
const args = hideBin(process.argv);
|
|
13
13
|
|
|
14
|
-
// Stop here if docker process not running and command isn't version or origin which don't require docker
|
|
15
|
-
if(!_.services && !(args[0] === 'origin' || args[0] === '--version')) process.exit();
|
|
16
|
-
|
|
17
14
|
(async () => {
|
|
18
15
|
const updateNotifier = (await import('update-notifier')).default;
|
|
19
16
|
const pkg = require('./package.json');
|
|
@@ -36,7 +36,7 @@ module.exports = [
|
|
|
36
36
|
{
|
|
37
37
|
type: 'confirm',
|
|
38
38
|
name: 'check',
|
|
39
|
-
message: `Deprovisioning ${utilities.colorize(aws.slug(_.
|
|
39
|
+
message: `Deprovisioning ${utilities.colorize(aws.slug(_.repo_safe, answers.client, branch), 'error')} from ${utilities.colorize(answers.client, 'error')} AWS account, are you sure you want to continue?`,
|
|
40
40
|
default: false
|
|
41
41
|
}
|
|
42
42
|
]);
|
|
@@ -45,10 +45,10 @@ module.exports = [
|
|
|
45
45
|
process.exit(1);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
try { await aws.s3.removeS3Bucket(aws.slug(_.
|
|
48
|
+
try { await aws.s3.removeS3Bucket(aws.slug(_.repo_safe, answers.client, branch), answers.client); } catch(e) {}
|
|
49
49
|
|
|
50
50
|
try { await aws.cloudfront.removeCloudFrontDistribution(answers.id, answers.client); } catch(e) {}
|
|
51
51
|
|
|
52
|
-
try { await aws.cloudfront.removeCloudFrontFunction(aws.slug(_.
|
|
52
|
+
try { await aws.cloudfront.removeCloudFrontFunction(aws.slug(_.repo_safe, answers.client, branch), answers.client); } catch(e) {}
|
|
53
53
|
}
|
|
54
54
|
];
|
|
@@ -2,6 +2,7 @@ const _ = require('../../../globals.js');
|
|
|
2
2
|
const utilities = require('../libs/utilities');
|
|
3
3
|
const inquirer = require('inquirer');
|
|
4
4
|
const aws = require('../services/aws/index.js');
|
|
5
|
+
const email = require('../services/email.js');
|
|
5
6
|
|
|
6
7
|
module.exports = [
|
|
7
8
|
'key',
|
|
@@ -10,6 +11,7 @@ module.exports = [
|
|
|
10
11
|
async argv => {
|
|
11
12
|
let users = [];
|
|
12
13
|
let clients = [];
|
|
14
|
+
let sendEmail = false;
|
|
13
15
|
|
|
14
16
|
let answer = await inquirer.prompt([
|
|
15
17
|
{
|
|
@@ -59,6 +61,17 @@ module.exports = [
|
|
|
59
61
|
clients = answer.clients;
|
|
60
62
|
}
|
|
61
63
|
|
|
64
|
+
answer = await inquirer.prompt([
|
|
65
|
+
{
|
|
66
|
+
type: 'confirm',
|
|
67
|
+
name: 'check',
|
|
68
|
+
message: `Would you like to email out the credentials after creation (requires office365 credentials in ~/targets/misc.json)?`,
|
|
69
|
+
default: 'Y'
|
|
70
|
+
}
|
|
71
|
+
]);
|
|
72
|
+
|
|
73
|
+
sendEmail = answer.check
|
|
74
|
+
|
|
62
75
|
let credentials = {};
|
|
63
76
|
|
|
64
77
|
for(let i = 0; i < clients.length; i++){
|
|
@@ -84,10 +97,17 @@ module.exports = [
|
|
|
84
97
|
|
|
85
98
|
for(var user in credentials){
|
|
86
99
|
output += utilities.colorize(`\n${user}\n`, 'title');
|
|
100
|
+
|
|
101
|
+
let outputUser = '';
|
|
87
102
|
for(var client in credentials[user]){
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
103
|
+
outputUser += `\n[${client}]\n`;
|
|
104
|
+
outputUser += `aws_access_key_id = ${credentials[user][client].key}\n`;
|
|
105
|
+
outputUser += `aws_secret_access_key = ${credentials[user][client].secret}\n`;
|
|
106
|
+
}
|
|
107
|
+
output += outputUser;
|
|
108
|
+
|
|
109
|
+
if(sendEmail){
|
|
110
|
+
await email.send(_.config.users.find(d => d.username === user).email, 'New AWS Keys', null, outputUser);
|
|
91
111
|
}
|
|
92
112
|
}
|
|
93
113
|
|
|
@@ -94,7 +94,7 @@ module.exports = [
|
|
|
94
94
|
let infastructure;
|
|
95
95
|
|
|
96
96
|
try{
|
|
97
|
-
infastructure = await aws.static(aws.slug(_.
|
|
97
|
+
infastructure = await aws.static(aws.slug(_.repo_safe, answers.client, branch), answers.client, [{Key: 'repository', Value: _.repo}, {Key: 'environment', Value: branch}], credentials);
|
|
98
98
|
} catch(e){
|
|
99
99
|
console.log(e.message);
|
|
100
100
|
process.exit(1);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const ora = require('ora');
|
|
3
|
+
const crypto = require('crypto');
|
|
3
4
|
|
|
4
5
|
// Text
|
|
5
6
|
module.exports.capitalize = str => str.charAt(0).toUpperCase() + str.slice(1);
|
|
@@ -96,4 +97,21 @@ module.exports.encode = (username, password) => {
|
|
|
96
97
|
"Content-Type": "application/json",
|
|
97
98
|
"Authorization": `Basic ${base64data}`
|
|
98
99
|
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
module.exports.s3Safe = (name) => {
|
|
103
|
+
let safe = name;
|
|
104
|
+
let hash = crypto.createHash('md5').update(name).digest('hex');
|
|
105
|
+
let suffix = `-${hash.substring(0, 8)}`;
|
|
106
|
+
let prefix = 'fw-auto-';
|
|
107
|
+
|
|
108
|
+
safe = safe.substring(0, (63 - suffix.length - prefix.length));
|
|
109
|
+
safe = safe.replace(/[^a-zA-Z0-9-_. ]/g, ""); // Remove special chars except . _ - as these are all transformed into -
|
|
110
|
+
safe = safe.toLowerCase();
|
|
111
|
+
safe = `${prefix}${safe}`;
|
|
112
|
+
safe = `${safe}${suffix}`;
|
|
113
|
+
safe = safe.replace(/\./g, '-');
|
|
114
|
+
safe = safe.replace(/\_/g, '-');
|
|
115
|
+
|
|
116
|
+
return safe;
|
|
99
117
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
const { s3Safe } = require("../../libs/utilities.js");
|
|
2
|
+
|
|
1
3
|
module.exports.s3 = require("./s3.js");
|
|
2
4
|
module.exports.cloudfront = require("./cloudfront.js");
|
|
3
5
|
module.exports.iam = require("./iam.js");
|
|
4
6
|
|
|
5
|
-
module.exports.slug = (repo, client, branch) =>
|
|
7
|
+
module.exports.slug = (repo, client, branch) => s3Safe(`${branch}-${repo}-${client}`);
|
|
6
8
|
|
|
7
|
-
module.exports.clients = ['fishawack', 'abbvie', 'sanofigenzyme', 'gsk', 'janssen', 'astrazeneca', 'ptc', 'jazz', 'pfizer', 'heron', 'novartis', 'training', 'merck', 'acadia', 'travere'];
|
|
9
|
+
module.exports.clients = ['fishawack', 'abbvie', 'sanofigenzyme', 'gsk', 'janssen', 'astrazeneca', 'ptc', 'jazz', 'pfizer', 'heron', 'novartis', 'training', 'merck', 'acadia', 'travere', 'roche', 'utc', 'bayer', 'alcon'];
|
|
8
10
|
|
|
9
11
|
module.exports.static = async (name, account, tags = [], credentials = []) => {
|
|
10
12
|
let s3 = await module.exports.s3.createS3Bucket(name, account, tags);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const nodemailer = require("nodemailer");
|
|
2
|
+
const { misc } = require('../libs/vars');
|
|
3
|
+
|
|
4
|
+
module.exports.send = async (to, subject, html, text, test = false, from = `digitalautomation@fishawack.com`) => {
|
|
5
|
+
let transporter = await module.exports.transport(test);
|
|
6
|
+
|
|
7
|
+
let info = await transporter.sendMail({
|
|
8
|
+
from,
|
|
9
|
+
to,
|
|
10
|
+
subject,
|
|
11
|
+
html,
|
|
12
|
+
text
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
if(test){
|
|
16
|
+
console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return info;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
module.exports.transport = async (test = false) => {
|
|
23
|
+
let username = misc?.nodemailer?.office365.username;
|
|
24
|
+
let password = misc?.nodemailer?.office365.password;
|
|
25
|
+
|
|
26
|
+
if(test){
|
|
27
|
+
let testAccount = await nodemailer.createTestAccount();
|
|
28
|
+
|
|
29
|
+
username = testAccount.user;
|
|
30
|
+
password = testAccount.pass;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let transporter = nodemailer.createTransport({
|
|
34
|
+
host: test ? 'smtp.ethereal.email' : 'smtp.office365.com',
|
|
35
|
+
port: 587,
|
|
36
|
+
secure: false,
|
|
37
|
+
auth: {
|
|
38
|
+
user: username,
|
|
39
|
+
pass: password,
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return transporter;
|
|
44
|
+
};
|
package/globals.js
CHANGED
|
@@ -34,15 +34,6 @@ try{
|
|
|
34
34
|
config = {};
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
if(args[0] !== 'diag' && args[0] !== 'diagnose'){
|
|
38
|
-
if(!config.diagnosis || semver.diff(config.diagnosis, diagnosis) === 'major'){
|
|
39
|
-
console.log(`${utilities.colorize(`@fishawack/lab-env`, 'title')} diagnosis is ${utilities.colorize(`outdated`, 'error')}.\n\nRun ${utilities.colorize(`fw diagnose`, 'success')} to reconfigure.`);
|
|
40
|
-
process.exit(1);
|
|
41
|
-
} else if(semver.diff(config.diagnosis, diagnosis) !== null){
|
|
42
|
-
console.log(`${utilities.colorize(`@fishawack/lab-env`, 'title')} diagnosis is ${utilities.colorize(`outdated`, 'warning')}.\n\nRun ${utilities.colorize(`fw diagnose`, 'success')} to reconfigure.`);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
37
|
try{
|
|
47
38
|
branch = process.env.BRANCH || process.env.CI_COMMIT_REF_NAME || require('git-branch').sync();
|
|
48
39
|
} catch(e){
|
|
@@ -132,8 +123,22 @@ try{
|
|
|
132
123
|
exec = `exec ${process.env.CI_BUILD_ID ? '-T' : ''}`;
|
|
133
124
|
method = running ? exec : 'run --rm --service-ports';
|
|
134
125
|
run = `${method} core bash -l`;
|
|
135
|
-
} catch(e){
|
|
136
|
-
|
|
126
|
+
} catch(e){}
|
|
127
|
+
|
|
128
|
+
// Always allow diagnose, diag, version, help and origin through
|
|
129
|
+
if(args[0] !== 'diag' && args[0] !== 'diagnose' && args[0] !== 'origin' && args[0] !== '--version' && args[0] !== '--help'){
|
|
130
|
+
// Stop here if diagnosis either unset or outdated
|
|
131
|
+
if(!config.diagnosis || semver.diff(config.diagnosis, diagnosis) === 'major'){
|
|
132
|
+
console.log(`${utilities.colorize(`@fishawack/lab-env`, 'title')} diagnosis is ${utilities.colorize(`outdated`, 'error')}.\n\nRun ${utilities.colorize(`fw diagnose`, 'success')} to reconfigure.`);
|
|
133
|
+
process.exit(1);
|
|
134
|
+
// Warn if diagnosis only minor/patch outdated
|
|
135
|
+
} else if(semver.diff(config.diagnosis, diagnosis) !== null){
|
|
136
|
+
console.log(`${utilities.colorize(`@fishawack/lab-env`, 'title')} diagnosis is ${utilities.colorize(`outdated`, 'warning')}.\n\nRun ${utilities.colorize(`fw diagnose`, 'success')} to reconfigure.`);
|
|
137
|
+
// Stop here if docker process not running
|
|
138
|
+
} else if(!services) {
|
|
139
|
+
console.log(`${utilities.colorize(`Docker`, 'info')} does not appear to be running...`);
|
|
140
|
+
process.exit();
|
|
141
|
+
}
|
|
137
142
|
}
|
|
138
143
|
|
|
139
144
|
module.exports = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fishawack/lab-env",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "Docker manager for FW",
|
|
5
5
|
"main": "cli.js",
|
|
6
6
|
"scripts": {
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"git-branch": "^2.0.1",
|
|
33
33
|
"glob": "7.1.7",
|
|
34
34
|
"inquirer": "8.1.2",
|
|
35
|
+
"nodemailer": "^6.7.8",
|
|
35
36
|
"ora": "5.4.1",
|
|
36
37
|
"semver": "7.3.4",
|
|
37
38
|
"update-notifier": "^6.0.2",
|