mirror of
https://github.com/morten-olsen/with-ssm.git
synced 2026-02-08 00:46:23 +01:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
815ac86873 | ||
|
|
14c4d5c386 | ||
|
|
00786d5508 |
@@ -117,7 +117,7 @@ override the SSM-resolved values. To avoid this:
|
||||
|
||||
- Use `.env.with-ssm` instead of `.env` for SSM references
|
||||
- Or use environment variable substitution if your app supports it:
|
||||
`${API_KEY:-SSM:/myapp/api-key}`
|
||||
`API_KEY=${API_KEY:-SSM:/myapp/api-key}`
|
||||
|
||||
### 🚀 Deployment Considerations
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
"@types/yargs": "^17.0.33",
|
||||
"@vercel/ncc": "^0.38.3",
|
||||
"@vitest/coverage-v8": "3.2.4",
|
||||
"dotenv": "^17.2.1",
|
||||
"eslint": "9.32.0",
|
||||
"eslint-config-prettier": "10.1.8",
|
||||
"eslint-plugin-import": "2.32.0",
|
||||
@@ -37,5 +36,8 @@
|
||||
"yargs": "^18.0.0"
|
||||
},
|
||||
"name": "@morten-olsen/with-ssm",
|
||||
"version": "1.0.0"
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@dotenvx/dotenvx": "^1.51.0"
|
||||
}
|
||||
}
|
||||
|
||||
91
pnpm-lock.yaml
generated
91
pnpm-lock.yaml
generated
@@ -7,6 +7,10 @@ settings:
|
||||
importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
'@dotenvx/dotenvx':
|
||||
specifier: ^1.51.0
|
||||
version: 1.51.0
|
||||
devDependencies:
|
||||
'@aws-sdk/client-ssm':
|
||||
specifier: ^3.863.0
|
||||
@@ -32,9 +36,6 @@ importers:
|
||||
'@vitest/coverage-v8':
|
||||
specifier: 3.2.4
|
||||
version: 3.2.4(vitest@3.2.4(@types/node@24.2.0))
|
||||
dotenv:
|
||||
specifier: ^17.2.1
|
||||
version: 17.2.1
|
||||
eslint:
|
||||
specifier: 9.32.0
|
||||
version: 9.32.0
|
||||
@@ -206,6 +207,16 @@ packages:
|
||||
resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@dotenvx/dotenvx@1.51.0':
|
||||
resolution: {integrity: sha512-CbMGzyOYSyFF7d4uaeYwO9gpSBzLTnMmSmTVpCZjvpJFV69qYbjYPpzNnCz1mb2wIvEhjWjRwQWuBzTO0jITww==}
|
||||
hasBin: true
|
||||
|
||||
'@ecies/ciphers@0.2.4':
|
||||
resolution: {integrity: sha512-t+iX+Wf5nRKyNzk8dviW3Ikb/280+aEJAnw9YXvCp2tYGPSkMki+NRY+8aNLmVFv3eNtMdvViPNOPxS8SZNP+w==}
|
||||
engines: {bun: '>=1', deno: '>=2', node: '>=16'}
|
||||
peerDependencies:
|
||||
'@noble/ciphers': ^1.0.0
|
||||
|
||||
'@esbuild/aix-ppc64@0.25.8':
|
||||
resolution: {integrity: sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -445,6 +456,18 @@ packages:
|
||||
'@jridgewell/trace-mapping@0.3.29':
|
||||
resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==}
|
||||
|
||||
'@noble/ciphers@1.3.0':
|
||||
resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==}
|
||||
engines: {node: ^14.21.3 || >=16}
|
||||
|
||||
'@noble/curves@1.9.7':
|
||||
resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==}
|
||||
engines: {node: ^14.21.3 || >=16}
|
||||
|
||||
'@noble/hashes@1.8.0':
|
||||
resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==}
|
||||
engines: {node: ^14.21.3 || >=16}
|
||||
|
||||
'@nodelib/fs.scandir@2.1.5':
|
||||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||
engines: {node: '>= 8'}
|
||||
@@ -1216,6 +1239,10 @@ packages:
|
||||
color-name@1.1.4:
|
||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||
|
||||
commander@11.1.0:
|
||||
resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
concat-map@0.0.1:
|
||||
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
||||
|
||||
@@ -1299,6 +1326,10 @@ packages:
|
||||
eastasianwidth@0.2.0:
|
||||
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
||||
|
||||
eciesjs@0.4.15:
|
||||
resolution: {integrity: sha512-r6kEJXDKecVOCj2nLMuXK/FCPeurW33+3JRpfXVbjLja3XUYFfD9I/JBreH6sUyzcm3G/YQboBjMla6poKeSdA==}
|
||||
engines: {bun: '>=1', deno: '>=2', node: '>=16'}
|
||||
|
||||
emoji-regex@10.4.0:
|
||||
resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==}
|
||||
|
||||
@@ -1822,6 +1853,10 @@ packages:
|
||||
isexe@2.0.0:
|
||||
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
|
||||
|
||||
isexe@3.1.1:
|
||||
resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
istanbul-lib-coverage@3.2.2:
|
||||
resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -2000,6 +2035,10 @@ packages:
|
||||
resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
object-treeify@1.1.33:
|
||||
resolution: {integrity: sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==}
|
||||
engines: {node: '>= 10'}
|
||||
|
||||
object.assign@4.1.7:
|
||||
resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -2612,6 +2651,11 @@ packages:
|
||||
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
|
||||
hasBin: true
|
||||
|
||||
which@4.0.0:
|
||||
resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==}
|
||||
engines: {node: ^16.13.0 || >=18.0.0}
|
||||
hasBin: true
|
||||
|
||||
why-is-node-running@2.3.0:
|
||||
resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -3047,6 +3091,22 @@ snapshots:
|
||||
|
||||
'@bcoe/v8-coverage@1.0.2': {}
|
||||
|
||||
'@dotenvx/dotenvx@1.51.0':
|
||||
dependencies:
|
||||
commander: 11.1.0
|
||||
dotenv: 17.2.1
|
||||
eciesjs: 0.4.15
|
||||
execa: 5.1.1
|
||||
fdir: 6.4.6(picomatch@4.0.3)
|
||||
ignore: 5.3.2
|
||||
object-treeify: 1.1.33
|
||||
picomatch: 4.0.3
|
||||
which: 4.0.0
|
||||
|
||||
'@ecies/ciphers@0.2.4(@noble/ciphers@1.3.0)':
|
||||
dependencies:
|
||||
'@noble/ciphers': 1.3.0
|
||||
|
||||
'@esbuild/aix-ppc64@0.25.8':
|
||||
optional: true
|
||||
|
||||
@@ -3209,6 +3269,14 @@ snapshots:
|
||||
'@jridgewell/resolve-uri': 3.1.2
|
||||
'@jridgewell/sourcemap-codec': 1.5.4
|
||||
|
||||
'@noble/ciphers@1.3.0': {}
|
||||
|
||||
'@noble/curves@1.9.7':
|
||||
dependencies:
|
||||
'@noble/hashes': 1.8.0
|
||||
|
||||
'@noble/hashes@1.8.0': {}
|
||||
|
||||
'@nodelib/fs.scandir@2.1.5':
|
||||
dependencies:
|
||||
'@nodelib/fs.stat': 2.0.5
|
||||
@@ -4212,6 +4280,8 @@ snapshots:
|
||||
|
||||
color-name@1.1.4: {}
|
||||
|
||||
commander@11.1.0: {}
|
||||
|
||||
concat-map@0.0.1: {}
|
||||
|
||||
config-chain@1.1.13:
|
||||
@@ -4291,6 +4361,13 @@ snapshots:
|
||||
|
||||
eastasianwidth@0.2.0: {}
|
||||
|
||||
eciesjs@0.4.15:
|
||||
dependencies:
|
||||
'@ecies/ciphers': 0.2.4(@noble/ciphers@1.3.0)
|
||||
'@noble/ciphers': 1.3.0
|
||||
'@noble/curves': 1.9.7
|
||||
'@noble/hashes': 1.8.0
|
||||
|
||||
emoji-regex@10.4.0: {}
|
||||
|
||||
emoji-regex@8.0.0: {}
|
||||
@@ -4913,6 +4990,8 @@ snapshots:
|
||||
|
||||
isexe@2.0.0: {}
|
||||
|
||||
isexe@3.1.1: {}
|
||||
|
||||
istanbul-lib-coverage@3.2.2: {}
|
||||
|
||||
istanbul-lib-report@3.0.1:
|
||||
@@ -5075,6 +5154,8 @@ snapshots:
|
||||
|
||||
object-keys@1.1.1: {}
|
||||
|
||||
object-treeify@1.1.33: {}
|
||||
|
||||
object.assign@4.1.7:
|
||||
dependencies:
|
||||
call-bind: 1.0.8
|
||||
@@ -5758,6 +5839,10 @@ snapshots:
|
||||
dependencies:
|
||||
isexe: 2.0.0
|
||||
|
||||
which@4.0.0:
|
||||
dependencies:
|
||||
isexe: 3.1.1
|
||||
|
||||
why-is-node-running@2.3.0:
|
||||
dependencies:
|
||||
siginfo: 2.0.0
|
||||
|
||||
@@ -5,7 +5,6 @@ import { exec } from './utils/exec.js';
|
||||
import { getEnv } from './utils/env.js';
|
||||
import { replaceParams } from './utils/ssm.js';
|
||||
|
||||
const main = async () => {
|
||||
const argv = await yargs(hideBin(process.argv))
|
||||
.usage('Usage: $0 [options] -- <command>')
|
||||
.option('region', {
|
||||
@@ -44,9 +43,3 @@ const main = async () => {
|
||||
env,
|
||||
args: commandArgs,
|
||||
});
|
||||
};
|
||||
|
||||
main().catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
const splitArgs = (args: string[]) => {
|
||||
const separatorIndex = args.indexOf('--');
|
||||
const actionArgs = args.slice(0, separatorIndex);
|
||||
const command = args[separatorIndex + 1];
|
||||
const commandArgs = args.slice(separatorIndex + 2);
|
||||
|
||||
return {
|
||||
actionArgs,
|
||||
command,
|
||||
commandArgs,
|
||||
};
|
||||
};
|
||||
|
||||
export { splitArgs };
|
||||
@@ -2,7 +2,7 @@ import { existsSync } from 'node:fs';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import { parse } from 'dotenv';
|
||||
import { parse } from '@dotenvx/dotenvx';
|
||||
|
||||
import { debug } from './debug.js';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { GetParametersCommand, SSMClient } from '@aws-sdk/client-ssm';
|
||||
import { GetParametersCommand, SSMClient, type Parameter } from '@aws-sdk/client-ssm';
|
||||
|
||||
import { debug } from './debug.js';
|
||||
|
||||
@@ -30,18 +30,42 @@ const replaceParams = async (
|
||||
return env;
|
||||
}
|
||||
|
||||
// Chunk names into groups of 10 (AWS SSM GetParametersCommand limit)
|
||||
const chunks: string[][] = [];
|
||||
debug(`Chunking ${names.length} names into groups of 10`);
|
||||
for (let i = 0; i < names.length; i += 10) {
|
||||
chunks.push(names.slice(i, i + 10));
|
||||
}
|
||||
|
||||
debug(`Processing ${chunks.length} chunks`);
|
||||
|
||||
// Fetch parameters in chunks and combine results
|
||||
const allParams: Parameter[] = [];
|
||||
const allInvalidParams: string[] = [];
|
||||
|
||||
for (const chunk of chunks) {
|
||||
const command = new GetParametersCommand({
|
||||
Names: names,
|
||||
Names: chunk,
|
||||
WithDecryption: true,
|
||||
});
|
||||
|
||||
const response = await ssm.send(command);
|
||||
if (response.InvalidParameters?.length || 0 > 0) {
|
||||
console.error('Invalid SSM parameters', response.InvalidParameters);
|
||||
|
||||
if (response.Parameters) {
|
||||
allParams.push(...response.Parameters);
|
||||
}
|
||||
|
||||
if (response.InvalidParameters) {
|
||||
allInvalidParams.push(...response.InvalidParameters);
|
||||
}
|
||||
}
|
||||
|
||||
if (allInvalidParams.length > 0) {
|
||||
console.error('Invalid SSM parameters', allInvalidParams);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const params = response.Parameters ?? [];
|
||||
const params = allParams;
|
||||
|
||||
return Object.fromEntries(
|
||||
Object.entries(env).map(([key, value]) => {
|
||||
|
||||
Reference in New Issue
Block a user