ac-awssecrets 2.4.3 → 2.5.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 +28 -0
- package/index.js +150 -21
- package/package.json +5 -5
- package/test/config.js +1 -1
- package/g.sh +0 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
|
|
2
|
+
# [2.5.0](https://github.com/admiralcloud/ac-awssecrets/compare/v2.4.4..v2.5.0) (2025-05-06 18:01:30)
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
### Feature
|
|
6
|
+
|
|
7
|
+
* **App:** Allow batch fetching secret parameters | MP | [0d74ae3d45edde466aa36ca15e3f3a689676cc37](https://github.com/admiralcloud/ac-awssecrets/commit/0d74ae3d45edde466aa36ca15e3f3a689676cc37)
|
|
8
|
+
To speed up processes, this version now allows batch fetching of secret parameters
|
|
9
|
+
Related issues:
|
|
10
|
+
### Tests
|
|
11
|
+
|
|
12
|
+
* **App:** Fixed test | MP | [996dabf3f6287150da5aaa048bcb2c3b7aa9a289](https://github.com/admiralcloud/ac-awssecrets/commit/996dabf3f6287150da5aaa048bcb2c3b7aa9a289)
|
|
13
|
+
Fixed test
|
|
14
|
+
Related issues:
|
|
15
|
+
### Chores
|
|
16
|
+
|
|
17
|
+
* **App:** Updated packages | MP | [42be94ad3cb396fc40f4300eec4463d6cfe18b3a](https://github.com/admiralcloud/ac-awssecrets/commit/42be94ad3cb396fc40f4300eec4463d6cfe18b3a)
|
|
18
|
+
Updated packages
|
|
19
|
+
Related issues:
|
|
20
|
+
|
|
21
|
+
## [2.4.4](https://github.com/admiralcloud/ac-awssecrets/compare/v2.4.3..v2.4.4) (2025-04-20 06:17:50)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### Bug Fix
|
|
25
|
+
|
|
26
|
+
* **App:** Package updates | MP | [fda6b66737639aaaefab76ec6d0cd91240039dd2](https://github.com/admiralcloud/ac-awssecrets/commit/fda6b66737639aaaefab76ec6d0cd91240039dd2)
|
|
27
|
+
Package updates
|
|
28
|
+
Related issues:
|
|
1
29
|
|
|
2
30
|
## [2.4.3](https://github.com/admiralcloud/ac-awssecrets/compare/v2.4.2..v2.4.3) (2025-04-19 18:41:08)
|
|
3
31
|
|
package/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const { SecretsManagerClient, GetSecretValueCommand } = require('@aws-sdk/client-secrets-manager')
|
|
2
|
-
const { SSMClient, GetParameterCommand, GetParametersByPathCommand } = require("@aws-sdk/client-ssm")
|
|
2
|
+
const { SSMClient, GetParameterCommand, GetParametersCommand, GetParametersByPathCommand } = require("@aws-sdk/client-ssm")
|
|
3
3
|
|
|
4
4
|
const testConfig = require('./test/config')
|
|
5
5
|
const functionName = 'ac-awsSecrets'.padEnd(15)
|
|
@@ -93,14 +93,127 @@ const awsSecrets = () => {
|
|
|
93
93
|
|
|
94
94
|
const loadSecretParameters = async({ secretParameters = [], config = {}, testMode = 0, debug = false, throwError = false, region = 'eu-central-1' } = {}) => {
|
|
95
95
|
const environment = config?.environment || process.env.NODE_ENV || 'development'
|
|
96
|
-
|
|
96
|
+
|
|
97
97
|
const awsConfig = {
|
|
98
98
|
region
|
|
99
99
|
}
|
|
100
100
|
const ssmClient = new SSMClient(awsConfig)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
|
|
102
|
+
// Process parameters in batches of 10 (AWS limit for GetParametersCommand)
|
|
103
|
+
const processBatchedParameters = async(paramList) => {
|
|
104
|
+
// Skip if no parameters
|
|
105
|
+
if (paramList.length === 0) return
|
|
106
|
+
|
|
107
|
+
// Split parameters into batches of 10
|
|
108
|
+
const batchSize = 10
|
|
109
|
+
const batches = []
|
|
110
|
+
|
|
111
|
+
for (let i = 0; i < paramList.length; i += batchSize) {
|
|
112
|
+
batches.push(paramList.slice(i, i + batchSize))
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Process each batch
|
|
116
|
+
for (const batch of batches) {
|
|
117
|
+
if (testMode === 3) {
|
|
118
|
+
// For test mode, process individually as before
|
|
119
|
+
await Promise.all(batch.map(async param => {
|
|
120
|
+
const parameterName = `/${environment}/${param.name}`
|
|
121
|
+
const found = testConfig.parameterStore.find(item => item.name === parameterName)
|
|
122
|
+
let value = found?.value
|
|
123
|
+
|
|
124
|
+
if (param.json && value) {
|
|
125
|
+
try {
|
|
126
|
+
value = JSON.parse(value)
|
|
127
|
+
}
|
|
128
|
+
catch (e) {
|
|
129
|
+
console.error('%s | %s | %s', functionName, parameterName, e?.message)
|
|
130
|
+
if (throwError) throw e
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (debug) {
|
|
135
|
+
console.warn('P %s | T %s | V %j', parameterName, typeof value, value)
|
|
136
|
+
}
|
|
137
|
+
setValue(config, {
|
|
138
|
+
path: (param.path || param.name),
|
|
139
|
+
value,
|
|
140
|
+
array: param.array || false,
|
|
141
|
+
property: param.property,
|
|
142
|
+
merge: param.merge || false
|
|
143
|
+
})
|
|
144
|
+
}))
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
// For production mode, use GetParametersCommand to fetch multiple parameters at once
|
|
148
|
+
try {
|
|
149
|
+
// Get parameter names for this batch
|
|
150
|
+
const parameterNames = batch.map(param => `/${environment}/${param.name}`)
|
|
151
|
+
|
|
152
|
+
// Fetch all parameters in this batch with a single API call
|
|
153
|
+
const command = new GetParametersCommand({
|
|
154
|
+
Names: parameterNames,
|
|
155
|
+
WithDecryption: true
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
const response = await ssmClient.send(command)
|
|
159
|
+
const parameters = response?.Parameters || []
|
|
160
|
+
|
|
161
|
+
// Process each parameter
|
|
162
|
+
await Promise.all(parameters.map(async parameter => {
|
|
163
|
+
// Find corresponding parameter config
|
|
164
|
+
const paramName = parameter.Name
|
|
165
|
+
const paramConfig = batch.find(p => `/${environment}/${p.name}` === paramName)
|
|
166
|
+
|
|
167
|
+
if (!paramConfig) return // Skip if no matching config found
|
|
168
|
+
|
|
169
|
+
let value = parameter.Value
|
|
170
|
+
|
|
171
|
+
if (paramConfig.json && value) {
|
|
172
|
+
try {
|
|
173
|
+
value = JSON.parse(value)
|
|
174
|
+
}
|
|
175
|
+
catch (e) {
|
|
176
|
+
console.error('%s | %s | %s', functionName, paramName, e?.message)
|
|
177
|
+
if (throwError) throw e
|
|
178
|
+
return // Skip this parameter if JSON parsing fails
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (debug) {
|
|
183
|
+
console.warn('P %s | T %s | V %j', paramName, typeof value, value)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
setValue(config, {
|
|
187
|
+
path: (paramConfig.path || paramConfig.name),
|
|
188
|
+
value,
|
|
189
|
+
array: paramConfig.array || false,
|
|
190
|
+
property: paramConfig.property,
|
|
191
|
+
merge: paramConfig.merge || false
|
|
192
|
+
})
|
|
193
|
+
}))
|
|
194
|
+
|
|
195
|
+
// Handle invalid parameters
|
|
196
|
+
if (response?.InvalidParameters?.length > 0) {
|
|
197
|
+
console.error('%s | Invalid parameters: %j', functionName, response.InvalidParameters)
|
|
198
|
+
if (throwError) {
|
|
199
|
+
throw new Error(`Invalid parameters: ${response.InvalidParameters.join(', ')}`)
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
catch (e) {
|
|
204
|
+
console.error('%s | Batch parameter fetch error: %s', functionName, e?.message)
|
|
205
|
+
if (throwError) throw e
|
|
206
|
+
|
|
207
|
+
// Fallback: process parameters individually if batch fails
|
|
208
|
+
await Promise.all(batch.map(param => getSecretParameter(param)))
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Keep the original getSecretParameter as fallback
|
|
215
|
+
const getSecretParameter = async(param) => {
|
|
216
|
+
const parameterName = `/${environment}/${param.name}`
|
|
104
217
|
try {
|
|
105
218
|
let value
|
|
106
219
|
if (testMode === 3) {
|
|
@@ -118,26 +231,25 @@ const awsSecrets = () => {
|
|
|
118
231
|
const response = await ssmClient.send(command)
|
|
119
232
|
value = response?.Parameter?.Value
|
|
120
233
|
}
|
|
121
|
-
|
|
234
|
+
|
|
122
235
|
// Extract and return the parameter value
|
|
123
|
-
if (json) {
|
|
236
|
+
if (param.json) {
|
|
124
237
|
value = JSON.parse(value)
|
|
125
238
|
}
|
|
126
|
-
|
|
239
|
+
|
|
127
240
|
if (debug) {
|
|
128
241
|
console.warn('P %s | T %s | V %j', parameterName, typeof value, value)
|
|
129
242
|
}
|
|
130
|
-
setValue(config, { path: (path || name), value, array, property, merge })
|
|
131
|
-
|
|
243
|
+
setValue(config, { path: (param.path || param.name), value, array: param.array, property: param.property, merge: param.merge })
|
|
132
244
|
}
|
|
133
245
|
catch (e) {
|
|
134
246
|
console.error('%s | %s | %s', functionName, parameterName, e?.message)
|
|
135
247
|
if (throwError) throw e
|
|
136
248
|
}
|
|
137
249
|
}
|
|
138
|
-
|
|
139
|
-
//
|
|
140
|
-
const getSecretParametersByPath = async({ name, json = false, array
|
|
250
|
+
|
|
251
|
+
// Keep the original getSecretParametersByPath for wildcard parameters
|
|
252
|
+
const getSecretParametersByPath = async({ path, name, json = false, array, property, merge }) => {
|
|
141
253
|
if (!path) throw new Error('pathMustBeSet')
|
|
142
254
|
const parameterName = `/${environment}/${name}`
|
|
143
255
|
try {
|
|
@@ -169,14 +281,14 @@ const awsSecrets = () => {
|
|
|
169
281
|
const response = await ssmClient.send(command)
|
|
170
282
|
valueArray = response?.Parameters
|
|
171
283
|
}
|
|
172
|
-
|
|
284
|
+
|
|
173
285
|
for (const item of valueArray) {
|
|
174
286
|
let value = item?.Value
|
|
175
287
|
// Extract and return the parameter value
|
|
176
288
|
if (json) {
|
|
177
289
|
value = JSON.parse(value)
|
|
178
290
|
}
|
|
179
|
-
|
|
291
|
+
|
|
180
292
|
if (debug) {
|
|
181
293
|
console.warn('P %s | T %s | V %j', item?.Name, typeof value, value)
|
|
182
294
|
}
|
|
@@ -188,13 +300,30 @@ const awsSecrets = () => {
|
|
|
188
300
|
if (throwError) throw e
|
|
189
301
|
}
|
|
190
302
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
303
|
+
|
|
304
|
+
// Filter out parameters with ignoreInTestMode = true in test environment
|
|
305
|
+
let filteredParams = secretParameters
|
|
306
|
+
if (environment === 'test') {
|
|
307
|
+
filteredParams = secretParameters.filter(param => !param.ignoreInTestMode)
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Add debug if needed
|
|
311
|
+
if (debug) {
|
|
312
|
+
filteredParams.forEach(param => param.debug = true)
|
|
197
313
|
}
|
|
314
|
+
|
|
315
|
+
// Split parameters into regular and wildcard ones
|
|
316
|
+
const wildcardParams = filteredParams.filter(param => param.name.endsWith('*'))
|
|
317
|
+
const regularParams = filteredParams.filter(param => !param.name.endsWith('*'))
|
|
318
|
+
|
|
319
|
+
// Process parameters in parallel
|
|
320
|
+
await Promise.all([
|
|
321
|
+
// Process regular parameters in batches
|
|
322
|
+
processBatchedParameters(regularParams),
|
|
323
|
+
|
|
324
|
+
// Process wildcard parameters individually (using original method)
|
|
325
|
+
...wildcardParams.map(param => getSecretParametersByPath(param))
|
|
326
|
+
])
|
|
198
327
|
}
|
|
199
328
|
|
|
200
329
|
|
package/package.json
CHANGED
|
@@ -3,17 +3,17 @@
|
|
|
3
3
|
"author": "Mark Poepping (https://www.admiralcloud.com)",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": "admiralcloud/ac-awssecrets",
|
|
6
|
-
"version": "2.
|
|
6
|
+
"version": "2.5.0",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@aws-sdk/client-secrets-manager": "^3.
|
|
9
|
-
"@aws-sdk/client-ssm": "^3.
|
|
8
|
+
"@aws-sdk/client-secrets-manager": "^3.803.0",
|
|
9
|
+
"@aws-sdk/client-ssm": "^3.803.0"
|
|
10
10
|
},
|
|
11
11
|
"devDependencies": {
|
|
12
|
-
"ac-semantic-release": "^0.4.
|
|
12
|
+
"ac-semantic-release": "^0.4.6",
|
|
13
13
|
"c8": "^10.1.3",
|
|
14
14
|
"chai": "^4.x",
|
|
15
15
|
"eslint": "9.x",
|
|
16
|
-
"mocha": "^11.
|
|
16
|
+
"mocha": "^11.2.2"
|
|
17
17
|
},
|
|
18
18
|
"scripts": {
|
|
19
19
|
"test": "NODE_ENV=test mocha --reporter spec --bail",
|
package/test/config.js
CHANGED
|
@@ -36,7 +36,7 @@ const secretParameters = [
|
|
|
36
36
|
{ name: 'configVar5.path', json: true },
|
|
37
37
|
{ name: 'configVar6', json: true },
|
|
38
38
|
{ name: 'aws', json: true, merge: true },
|
|
39
|
-
{ name: 'db/*', json: true, merge: true, path: 'db' }
|
|
39
|
+
{ name: 'db/*', json: true, merge: true, path: 'db', array: true }
|
|
40
40
|
]
|
|
41
41
|
|
|
42
42
|
const parameterStore = [
|
package/g.sh
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
aws ssm get-parameters-by-path \
|
|
3
|
-
--path "/development" \
|
|
4
|
-
--recursive \
|
|
5
|
-
--profile dev.mfa --region eu-central-1 \
|
|
6
|
-
--output json | \
|
|
7
|
-
jq '.Parameters[] |
|
|
8
|
-
{Name: .Name}'
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
{"secret":"L4w,UU3g;NAh)e6,HV(TTzUZ2G>","name":"acauth","valueHasJSON":"true","defaultApps":{"acapp":"8d09356a-042f-4d4a-9c6f-935329000969","embedlink": "5ffd8ff6-2aeb-44b0-8a6c-f413de58df3c"},"passwordAlgorithm":"aes-256-ctr","password":"8gZVqjzKN@g4XdD7Cq#9qAPh>iPdKNkr"}
|