ac-awssecrets 1.1.5 → 2.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/.acsemver.js +1 -1
- package/.eslintrc.js +5 -2
- package/.github/workflows/node.js.yml +30 -0
- package/CHANGELOG.md +53 -0
- package/README.md +130 -9
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +116 -0
- package/coverage/lcov-report/index.js.html +610 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +196 -0
- package/coverage/lcov.info +174 -0
- package/index.js +153 -163
- package/package.json +9 -7
- package/test/config.js +130 -0
- package/test/test.js +98 -4
package/index.js
CHANGED
|
@@ -1,182 +1,172 @@
|
|
|
1
|
-
const
|
|
2
|
-
const
|
|
3
|
-
|
|
1
|
+
const { SecretsManagerClient, GetSecretValueCommand } = require("@aws-sdk/client-secrets-manager");
|
|
2
|
+
const { fromIni } = require("@aws-sdk/credential-providers")
|
|
3
|
+
|
|
4
|
+
const testConfig = require('./test/config')
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
|
-
|
|
7
|
-
*/
|
|
7
|
+
* Replaces configuration variables with secrets
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const multiSecrets = _.get(params, 'multisecrets', [])
|
|
12
|
-
const secrets = _.get(params, 'secrets', [])
|
|
13
|
-
let config = _.get(params, 'config', {}) // the config object -> will be changed by reference
|
|
14
|
-
const environment = _.get(config, 'environment', 'development')
|
|
15
|
-
|
|
16
|
-
const region = _.get(params, 'aws.region', 'eu-central-1')
|
|
17
|
-
const endpoint = _.find(awsEndpoints, { region })
|
|
18
|
-
const client = new AWS.SecretsManager({
|
|
19
|
-
accessKeyId: _.get(params, 'aws.accessKeyId'),
|
|
20
|
-
secretAccessKey: _.get(params, 'aws.secretAccessKey'),
|
|
21
|
-
region: region,
|
|
22
|
-
endpoint: _.get(endpoint, 'endpoint')
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
let result = []
|
|
26
|
-
async.series({
|
|
27
|
-
fetchPlacholders: (done) => {
|
|
28
|
-
if (!_.size(multiSecrets)) return done()
|
|
29
|
-
// some keys can have multiple entries (e.g. cloudfrontCOnfigs can have 1 - n entries)
|
|
30
|
-
// we have to fetch them first from a secret and add them to the secrets to fetch
|
|
31
|
-
|
|
32
|
-
async.each(multiSecrets, (secret, itDone) => {
|
|
33
|
-
let secretName = (config.environment === 'test' ? 'test.' : '') + _.get(secret, 'name')
|
|
34
|
-
|
|
35
|
-
client.getSecretValue({ SecretId: secretName }, function(err, data) {
|
|
36
|
-
if (err) {
|
|
37
|
-
if (_.get(secret, 'ignoreInTestMode')) return itDone()
|
|
38
|
-
if (_.get(secret, 'ignoreIfMissing')) return itDone() // this is an optional key
|
|
39
|
-
|
|
40
|
-
console.error('Fetching secret %s failed', secretName, err)
|
|
41
|
-
return itDone({ message: err, additionalInfo: { key: secretName } })
|
|
42
|
-
}
|
|
43
|
-
if (!_.get(data, 'SecretString')) {
|
|
44
|
-
console.warn('Secret %s NOT avaialble', secretName, _.get(data, 'SecretString'))
|
|
45
|
-
return itDone()
|
|
46
|
-
}
|
|
9
|
+
KEY is the variable name
|
|
10
|
+
NAME is the name of the secret
|
|
47
11
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
value = JSON.parse(_.get(data, 'SecretString'))
|
|
51
|
-
}
|
|
52
|
-
catch (e) {
|
|
53
|
-
value = _.get(data, 'SecretString.values')
|
|
54
|
-
}
|
|
12
|
+
OPT
|
|
13
|
+
serverName
|
|
55
14
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
15
|
+
MULTISECRETS
|
|
16
|
+
Multisecrets -> the secret contains a list of secrets that should be fetched
|
|
17
|
+
*
|
|
18
|
+
* TESTMODES
|
|
19
|
+
* 3 -> use secrets from testConfig
|
|
20
|
+
*/
|
|
62
21
|
|
|
63
|
-
|
|
64
|
-
_.forEach(value, (item) => {
|
|
65
|
-
secrets.push({
|
|
66
|
-
key: secret.key,
|
|
67
|
-
name: item,
|
|
68
|
-
type: 'arrayObject'
|
|
69
|
-
})
|
|
70
|
-
})
|
|
71
|
-
return itDone()
|
|
72
|
-
})
|
|
73
|
-
}, done)
|
|
74
|
-
},
|
|
75
|
-
fetchSecrets: (done) => {
|
|
76
|
-
if (!_.size(secrets)) return done()
|
|
77
|
-
async.each(secrets, (secret, itDone) => {
|
|
78
|
-
if (environment === 'test' && _.get(secret, 'ignoreInTestMode')) return itDone()
|
|
79
|
-
// key is the local configuration path
|
|
80
|
-
let key = _.get(secret, 'key')
|
|
81
|
-
// secret name is the name used to fetch the secret
|
|
82
|
-
let secretName = (config.environment === 'test' ? 'test.' : '') + _.get(secret, 'name') + (_.get(secret, 'suffix') ? '.' + _.get(secret, 'suffix') : '')
|
|
83
|
-
|
|
84
|
-
client.getSecretValue({ SecretId: secretName }, function(err, data) {
|
|
85
|
-
if (err) {
|
|
86
|
-
if (_.get(secret, 'ignoreIfMissing')) return itDone() // this is an optional key
|
|
87
|
-
|
|
88
|
-
console.error('Fetching secret %s failed', secretName, _.get(err, 'message', err))
|
|
89
|
-
return itDone({ message: _.get(err, 'message', err), additionalInfo: { key: secretName } })
|
|
90
|
-
}
|
|
91
|
-
if (!_.get(data, 'SecretString')) {
|
|
92
|
-
console.warn('Secret %s NOT avaialble', secretName, _.get(data, 'SecretString'))
|
|
93
|
-
return itDone()
|
|
94
|
-
}
|
|
22
|
+
const awsSecrets = () => {
|
|
95
23
|
|
|
96
|
-
|
|
97
|
-
try {
|
|
98
|
-
value = JSON.parse(_.get(data, 'SecretString'))
|
|
99
|
-
|
|
100
|
-
// if value is prefixed with JSON -> parse the value
|
|
101
|
-
if (_.get(value, 'valueHasJSON')) {
|
|
102
|
-
_.forEach(value, (val, key) => {
|
|
103
|
-
if (_.startsWith(val, 'JSON:')) {
|
|
104
|
-
try {
|
|
105
|
-
_.set(value, key, JSON.parse(val.substr(5)))
|
|
106
|
-
}
|
|
107
|
-
catch (e) {
|
|
108
|
-
throw e
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
})
|
|
112
|
-
// remove that entry
|
|
113
|
-
_.unset(value, 'valueHasJSON')
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
catch (e) {
|
|
117
|
-
value = _.get(data, 'SecretString')
|
|
118
|
-
}
|
|
24
|
+
const getKey = (obj, key) => key.split('.').reduce((acc, cur) => acc[cur], obj)
|
|
119
25
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
let existingValue = _.get(config, key, {})
|
|
26
|
+
const setKey = (obj, key, value ) => {
|
|
27
|
+
const [head, ...rest] = key.split('.')
|
|
28
|
+
!rest.length
|
|
29
|
+
? obj[head] = value
|
|
30
|
+
: setKey(obj[head], rest.join('.'), value)
|
|
31
|
+
}
|
|
127
32
|
|
|
128
|
-
if (secret.servers) {
|
|
129
|
-
if (_.isBoolean(secret.servers)) {
|
|
130
|
-
// LEGACY SUPPORT FOR OLD NOTATION - DEPRECATED - DO NOT USE ANY LONGER
|
|
131
|
-
existingValue = _.find(_.get(config, key + '.servers', []), { server: secret.serverName })
|
|
132
|
-
}
|
|
133
|
-
else {
|
|
134
|
-
// NEW NOTATION AS OBJECT
|
|
135
|
-
let match = {}
|
|
136
|
-
_.set(match, _.get(secret.servers, 'identifier'), _.get(secret.servers, 'value'))
|
|
137
|
-
existingValue = _.find(_.get(config, key, []), match)
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
if (_.get(secret, 'type') === 'array') {
|
|
141
|
-
let array = []
|
|
142
|
-
_.forEach(value, (val) => {
|
|
143
|
-
array.push(val)
|
|
144
|
-
})
|
|
145
|
-
value = _.concat(existingValue, array)
|
|
146
|
-
}
|
|
147
33
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
34
|
+
const functionName = 'ac-awsSecrets'.padEnd(15)
|
|
35
|
+
const loadSecrets = async({ secrets = [], multisecrets = [], config = {}, profile = process.env['profile'], testMode = 0, debug = false } = {}) => {
|
|
36
|
+
const environment = config?.environment || 'development'
|
|
37
|
+
|
|
38
|
+
const awsConfig = {
|
|
39
|
+
region: 'eu-central-1'
|
|
40
|
+
}
|
|
41
|
+
// credentials are determined from Lambda role.
|
|
42
|
+
// But you can also use a set profile
|
|
43
|
+
if (profile) {
|
|
44
|
+
console.error('%s | Using AWS profile | %s', functionName, profile)
|
|
45
|
+
awsConfig.credentials = fromIni({ profile })
|
|
46
|
+
}
|
|
47
|
+
const client = new SecretsManagerClient(awsConfig)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
const getSecret = async({ secret }) => {
|
|
51
|
+
const secretName = (environment === 'test' ? 'test.' : '') + secret?.name + (secret?.suffix ? '.' + secret?.suffix : '')
|
|
52
|
+
|
|
53
|
+
// TESTMODE
|
|
54
|
+
if (testMode === 3) {
|
|
55
|
+
// fetch from availableSecrets
|
|
56
|
+
let found = testConfig.availableSecrets.find(item => item.name === secret.name)
|
|
57
|
+
secret.value = found?.value
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
const command = new GetSecretValueCommand({
|
|
61
|
+
SecretId: secretName
|
|
62
|
+
})
|
|
63
|
+
try {
|
|
64
|
+
const response = await client.send(command)
|
|
65
|
+
if (response?.SecretString) {
|
|
66
|
+
secret.value = JSON.parse(response?.SecretString)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch(e) {
|
|
70
|
+
console.error('%s | %s | %s', functionName, secretName, e?.message)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return secret
|
|
74
|
+
}
|
|
158
75
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
76
|
+
const fetchSecrets = async({ secrets }) => {
|
|
77
|
+
// filter out secrets with ignoreInTestMode = true
|
|
78
|
+
if (environment === 'test') {
|
|
79
|
+
secrets = secrets.filter(secret => !secret.ignoreInTestMode)
|
|
80
|
+
}
|
|
81
|
+
return Promise.all(secrets.map(secret => getSecret({ secret })))
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// fetch placeholder
|
|
85
|
+
if (multisecrets.length > 0) {
|
|
86
|
+
// some keys can have multiple entries (e.g. cloudfrontCOnfigs can have 1 - n entries)
|
|
87
|
+
// we have to fetch them first from a secret and add them to the secrets to fetch
|
|
88
|
+
let secretsToAdd = await fetchSecrets({ secrets: multisecrets })
|
|
89
|
+
// iterate each multisecret and add the values as new secrets
|
|
90
|
+
secretsToAdd.forEach(secadd => {
|
|
91
|
+
let items = JSON.parse(secadd?.value?.values) || []
|
|
92
|
+
if (typeof items !== 'object' || items.length < 1) {
|
|
93
|
+
console.error('%s | %s | MultiSecret has no valid property values', functionName, secadd.name)
|
|
94
|
+
throw new Error('MultiSecret has no valid property values')
|
|
95
|
+
}
|
|
96
|
+
items.forEach(item => {
|
|
97
|
+
let p = {
|
|
98
|
+
key: secadd.key,
|
|
99
|
+
name: item,
|
|
100
|
+
type: 'arrayObject' // multisecrets contain multiple secrets that belong to the same config property (which is an array of objects)
|
|
101
|
+
}
|
|
102
|
+
secrets.push(p)
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (secrets.length > 0) {
|
|
108
|
+
await fetchSecrets({ secrets })
|
|
109
|
+
for (const secret of secrets) {
|
|
110
|
+
let existingValue = getKey(config, secret.key) || {}
|
|
111
|
+
let value = secret?.value
|
|
112
|
+
|
|
113
|
+
// convert values
|
|
114
|
+
if (typeof value === 'object') {
|
|
115
|
+
Object.keys(value).forEach((key) => {
|
|
116
|
+
let val = value[key]
|
|
117
|
+
if (val === 'true') val = true
|
|
118
|
+
else if (val === 'false') val = false
|
|
119
|
+
else if (typeof val === 'string' && val.startsWith('JSON:')) {
|
|
120
|
+
try {
|
|
121
|
+
val = JSON.parse(val.substring(5))
|
|
122
|
+
}
|
|
123
|
+
catch(e) {
|
|
124
|
+
console.error('%s | %s | JSON could not be parsed %j', functionName, secret.name, val)
|
|
125
|
+
throw new Error('invalidJSON')
|
|
126
|
+
}
|
|
164
127
|
}
|
|
165
|
-
|
|
166
|
-
result.push({ key, name: _.get(secret, 'name', '-') })
|
|
167
|
-
return itDone()
|
|
128
|
+
value[key] = val
|
|
168
129
|
})
|
|
169
|
-
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (secret.servers) {
|
|
133
|
+
if (typeof secret.servers === 'boolean') {
|
|
134
|
+
let servers = existingValue?.servers || []
|
|
135
|
+
config[secret.key].servers = servers.map(server => {
|
|
136
|
+
if (server.server === secret.serverName) {
|
|
137
|
+
server = { ...server, ...value }
|
|
138
|
+
}
|
|
139
|
+
return server
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
// NEW NOTATION AS OBJECT
|
|
144
|
+
/* TODO: Probably not used anywhere, so legacy is ok
|
|
145
|
+
let match = {}
|
|
146
|
+
_.set(match, _.get(secret.servers, 'identifier'), _.get(secret.servers, 'value'))
|
|
147
|
+
existingValue = _.find(_.get(config, key, []), match)
|
|
148
|
+
*/
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
else if (secret?.type === 'arrayObject') {
|
|
152
|
+
existingValue.push(value)
|
|
153
|
+
setKey(config, secret.key, existingValue)
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
if (Object.keys(existingValue).length === 0) {
|
|
157
|
+
setKey(config, secret.key, {})
|
|
158
|
+
}
|
|
159
|
+
existingValue = { ...existingValue, ...value }
|
|
160
|
+
setKey(config, secret.key, existingValue)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (secret?.log || debug) {
|
|
164
|
+
console.log('%s | %s | %j', functionName, secret?.name, existingValue)
|
|
165
|
+
}
|
|
170
166
|
}
|
|
171
|
-
}
|
|
172
|
-
return cb(err, _.orderBy(result, 'key'))
|
|
173
|
-
})
|
|
167
|
+
}
|
|
174
168
|
}
|
|
175
169
|
|
|
176
|
-
const awsEndpoints = [
|
|
177
|
-
{ region: 'eu-central-1', endpoint: 'https://secretsmanager.eu-central-1.amazonaws.com' }
|
|
178
|
-
]
|
|
179
|
-
|
|
180
170
|
return {
|
|
181
171
|
loadSecrets
|
|
182
172
|
}
|
package/package.json
CHANGED
|
@@ -3,19 +3,21 @@
|
|
|
3
3
|
"author": "Mark Poepping (https://www.admiralcloud.com)",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": "admiralcloud/ac-awssecrets",
|
|
6
|
-
"version": "
|
|
6
|
+
"version": "2.0.0",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"
|
|
9
|
-
"aws-sdk": "^
|
|
10
|
-
"lodash": "^4.17.21"
|
|
8
|
+
"@aws-sdk/client-secrets-manager": "^3.279.0",
|
|
9
|
+
"@aws-sdk/credential-providers": "^3.279.0"
|
|
11
10
|
},
|
|
12
11
|
"devDependencies": {
|
|
13
|
-
"ac-semantic-release": "^0.
|
|
12
|
+
"ac-semantic-release": "^0.3.5",
|
|
13
|
+
"chai": "^4.3.7",
|
|
14
14
|
"eslint": "8.x",
|
|
15
|
-
"mocha": "^
|
|
15
|
+
"mocha": "^10.2.0",
|
|
16
|
+
"nyc": "^15.1.0"
|
|
16
17
|
},
|
|
17
18
|
"scripts": {
|
|
18
|
-
"test": "mocha --reporter spec"
|
|
19
|
+
"test": "mocha --reporter spec",
|
|
20
|
+
"coverage": "./node_modules/nyc/bin/nyc.js report --reporter=lcov --reporter=text"
|
|
19
21
|
},
|
|
20
22
|
"engines": {
|
|
21
23
|
"node": ">=8.0.0"
|
package/test/config.js
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
const config = {
|
|
2
|
+
configVar1: {
|
|
3
|
+
c1: false
|
|
4
|
+
},
|
|
5
|
+
configVar2: {
|
|
6
|
+
servers: [
|
|
7
|
+
{ server: 'cacheRead', host: 'localhost', port: 6379 },
|
|
8
|
+
]
|
|
9
|
+
},
|
|
10
|
+
configVar4: {
|
|
11
|
+
api: {
|
|
12
|
+
port: 90
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
configVar5: {
|
|
16
|
+
path: {
|
|
17
|
+
cookie: false
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
aws: {
|
|
21
|
+
accessKeys: []
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const secrets = [
|
|
26
|
+
{ key: 'configVar1', name: 'simple' },
|
|
27
|
+
{ key: 'configVar2', name: 'server', servers: true, serverName: 'cacheRead' },
|
|
28
|
+
{ key: 'configVar4', name: 'json' },
|
|
29
|
+
{ key: 'configVar5.path', name: 'path' },
|
|
30
|
+
{ key: 'configVar6', name: 'notExistingLocally' },
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
const availableSecrets = [{
|
|
34
|
+
key: 'configVar1',
|
|
35
|
+
name: 'simple',
|
|
36
|
+
value: {
|
|
37
|
+
c1: 'true',
|
|
38
|
+
c2: 123,
|
|
39
|
+
c3: 'abc'
|
|
40
|
+
},
|
|
41
|
+
log: true
|
|
42
|
+
}, {
|
|
43
|
+
key: 'configVar2',
|
|
44
|
+
name: 'server',
|
|
45
|
+
value: {
|
|
46
|
+
port: 6360,
|
|
47
|
+
host: 'myRedisHost'
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
key: 'configVar3',
|
|
52
|
+
name: 'noSecret'
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
key: 'configVar4',
|
|
56
|
+
name: 'json',
|
|
57
|
+
value: {
|
|
58
|
+
api: 'JSON:{"url":"https://api.admiralcloud.com"}',
|
|
59
|
+
valueHasJSON: true
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
key: 'errorVar1',
|
|
64
|
+
name: 'invalidJSON',
|
|
65
|
+
value: {
|
|
66
|
+
api: 'JSON:abc',
|
|
67
|
+
valueHasJSON: true
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
key: 'configVar5.path',
|
|
72
|
+
name: 'path',
|
|
73
|
+
value: {
|
|
74
|
+
cookie: true
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
key: 'configVar6',
|
|
79
|
+
name: 'notExistingLocally',
|
|
80
|
+
value: {
|
|
81
|
+
prop1: 123,
|
|
82
|
+
prop2: 'abc'
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
key: 'aws.accessKeys',
|
|
87
|
+
name: 'aws.accessKeyConfigs',
|
|
88
|
+
value: {
|
|
89
|
+
values: '["aws.key1", "aws.key2"]'
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
key: 'aws.failedKeys',
|
|
94
|
+
name: 'aws.failedKeysConfig',
|
|
95
|
+
value: {
|
|
96
|
+
values: 123
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
key: 'aws.key1',
|
|
101
|
+
name: 'aws.key1',
|
|
102
|
+
value: {
|
|
103
|
+
accessKeyId: 'awsKey1',
|
|
104
|
+
secretAccessKey: 'awsSecret1'
|
|
105
|
+
}
|
|
106
|
+
},{
|
|
107
|
+
key: 'aws.key2',
|
|
108
|
+
name: 'aws.key2',
|
|
109
|
+
value: {
|
|
110
|
+
accessKeyId: 'awsKey2',
|
|
111
|
+
secretAccessKey: 'awsSecret2'
|
|
112
|
+
}
|
|
113
|
+
}]
|
|
114
|
+
|
|
115
|
+
const multisecrets = [
|
|
116
|
+
{ key: 'aws.accessKeys', name: 'aws.accessKeyConfigs' }
|
|
117
|
+
]
|
|
118
|
+
|
|
119
|
+
const multisecretsFail = [
|
|
120
|
+
{ key: 'aws.failedKeys', name: 'aws.failedKeysConfig' }
|
|
121
|
+
]
|
|
122
|
+
|
|
123
|
+
module.exports = {
|
|
124
|
+
config,
|
|
125
|
+
availableSecrets,
|
|
126
|
+
multisecretsFail,
|
|
127
|
+
secrets,
|
|
128
|
+
multisecrets
|
|
129
|
+
}
|
|
130
|
+
|
package/test/test.js
CHANGED
|
@@ -1,7 +1,101 @@
|
|
|
1
|
-
|
|
1
|
+
const { expect } = require('chai')
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
|
|
4
|
+
const awsSecrets = require('../index')
|
|
5
|
+
|
|
6
|
+
const testConfig = require('./config')
|
|
7
|
+
|
|
8
|
+
const multisecrets = testConfig?.multisecrets
|
|
9
|
+
const config = testConfig.config
|
|
10
|
+
let secrets = testConfig.secrets
|
|
11
|
+
|
|
12
|
+
// HELPER for console.log checks
|
|
13
|
+
const captureStream = (stream) => {
|
|
14
|
+
let oldWrite = stream.write
|
|
15
|
+
var buf = ''
|
|
16
|
+
stream.write = (chunk) => {
|
|
17
|
+
buf += chunk.toString()
|
|
18
|
+
oldWrite.apply(stream, arguments)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
unhook: () => {
|
|
23
|
+
stream.write = oldWrite
|
|
24
|
+
},
|
|
25
|
+
captured: () => {
|
|
26
|
+
return buf
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
describe('Reading secrets', () => {
|
|
33
|
+
it('Read secrets', async() => {
|
|
34
|
+
await awsSecrets.loadSecrets({ secrets, config, multisecrets, testMode: 3 })
|
|
35
|
+
//console.log(18, config)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('Check configVar1', async() => {
|
|
39
|
+
const expected = secrets.find(item => item.key === 'configVar1')
|
|
40
|
+
expect(config.configVar1).to.have.property('c1', true)
|
|
41
|
+
expect(config.configVar1).to.have.property('c2', expected.value.c2)
|
|
42
|
+
expect(config.configVar1).to.have.property('c3', expected.value.c3)
|
|
43
|
+
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('Check server', async() => {
|
|
47
|
+
const expected = secrets.find(item => item.key === 'configVar2')
|
|
48
|
+
expect(config.configVar2.servers[0]).to.have.property('port', expected.value.port)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('Check JSON', async() => {
|
|
52
|
+
expect(config.configVar4.api).to.have.property('url', 'https://api.admiralcloud.com')
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('Check path', async() => {
|
|
56
|
+
expect(config.configVar5.path).to.have.property('cookie', true)
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('Check non existing local config', async() => {
|
|
60
|
+
expect(config.configVar6).to.have.property('prop1', 123)
|
|
61
|
+
expect(config.configVar6).to.have.property('prop2', 'abc')
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it('Check multisecrets', async() => {
|
|
65
|
+
//console.log(50, config.aws.accessKeys)
|
|
66
|
+
expect(config.aws.accessKeys).to.have.length(2)
|
|
67
|
+
expect(config.aws.accessKeys[0]).to.have.property('accessKeyId', 'awsKey1')
|
|
68
|
+
expect(config.aws.accessKeys[1]).to.have.property('accessKeyId', 'awsKey2')
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
describe('Check errors', () => {
|
|
73
|
+
it('Check invalid JSON', async() => {
|
|
74
|
+
let errorSecrets = [
|
|
75
|
+
{ name: 'invalidJSON', key: 'errorVar1' }
|
|
76
|
+
]
|
|
77
|
+
try {
|
|
78
|
+
await awsSecrets.loadSecrets({ secrets: errorSecrets, config, testMode: 3 })
|
|
79
|
+
}
|
|
80
|
+
catch(e) {
|
|
81
|
+
expect(e).to.be.an('error')
|
|
82
|
+
expect(e).to.have.property('message', 'invalidJSON')
|
|
83
|
+
}
|
|
6
84
|
})
|
|
7
85
|
})
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
describe('Misc', () => {
|
|
89
|
+
var hook
|
|
90
|
+
beforeEach(function(){
|
|
91
|
+
hook = captureStream(process.stdout)
|
|
92
|
+
})
|
|
93
|
+
afterEach(function(){
|
|
94
|
+
hook.unhook()
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it('Read secrets with debug mode', async() => {
|
|
98
|
+
await awsSecrets.loadSecrets({ secrets, config, multisecrets, testMode: 3, debug: true })
|
|
99
|
+
expect(hook.captured()).to.include('ac-awsSecrets')
|
|
100
|
+
})
|
|
101
|
+
})
|