@bubltec/mycota-config 0.1.0-dev.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/LICENSE +21 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +76 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/ssm-config.d.ts +53 -0
- package/dist/ssm-config.d.ts.map +1 -0
- package/dist/ssm-config.js +119 -0
- package/dist/ssm-config.js.map +1 -0
- package/dist/ssm-config.spec.d.ts +2 -0
- package/dist/ssm-config.spec.d.ts.map +1 -0
- package/dist/ssm-config.spec.js +109 -0
- package/dist/ssm-config.spec.js.map +1 -0
- package/package.json +36 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Genome
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { loadSsmConfig, pushSsmConfig, cloneSsmNamespace, deleteSsmNamespace, } from './ssm-config.js';
|
|
3
|
+
const USAGE = `Usage:
|
|
4
|
+
mycota-config load --namespace <ns> --env <env> [--region <region>]
|
|
5
|
+
mycota-config push --namespace <ns> --env <env> --key <key> --value <value>
|
|
6
|
+
mycota-config clone --namespace <ns> --source <env> --target <env>
|
|
7
|
+
mycota-config delete --namespace <ns> --env <env>
|
|
8
|
+
|
|
9
|
+
'load' prints dotenv-format KEY=VALUE lines to stdout — pipe/redirect it
|
|
10
|
+
(e.g. \`mycota-config load --namespace myapp --env dev > .env\`) rather than
|
|
11
|
+
reading it off the terminal, since it contains real secret values.`;
|
|
12
|
+
function parseArgs(argv) {
|
|
13
|
+
const args = {};
|
|
14
|
+
for (let i = 0; i < argv.length; i += 2) {
|
|
15
|
+
const key = argv[i]?.replace(/^--/, '');
|
|
16
|
+
const value = argv[i + 1];
|
|
17
|
+
if (key && value !== undefined)
|
|
18
|
+
args[key] = value;
|
|
19
|
+
}
|
|
20
|
+
return args;
|
|
21
|
+
}
|
|
22
|
+
function requireArg(args, name) {
|
|
23
|
+
const value = args[name];
|
|
24
|
+
if (!value) {
|
|
25
|
+
console.error(`Missing required --${name}\n\n${USAGE}`);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
async function main() {
|
|
31
|
+
const [command, ...rest] = process.argv.slice(2);
|
|
32
|
+
const args = parseArgs(rest);
|
|
33
|
+
switch (command) {
|
|
34
|
+
case 'load': {
|
|
35
|
+
const config = await loadSsmConfig({
|
|
36
|
+
namespace: requireArg(args, 'namespace'),
|
|
37
|
+
env: requireArg(args, 'env'),
|
|
38
|
+
region: args.region,
|
|
39
|
+
});
|
|
40
|
+
for (const [key, value] of Object.entries(config)) {
|
|
41
|
+
console.log(`${key.toUpperCase().replace(/-/g, '_')}=${value}`);
|
|
42
|
+
}
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
case 'push': {
|
|
46
|
+
const written = await pushSsmConfig({ namespace: requireArg(args, 'namespace'), env: requireArg(args, 'env') }, { [requireArg(args, 'key')]: requireArg(args, 'value') });
|
|
47
|
+
console.error(written.length ? `Wrote: ${written.join(', ')}` : 'Nothing written (empty value).');
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
case 'clone': {
|
|
51
|
+
const written = await cloneSsmNamespace({
|
|
52
|
+
namespace: requireArg(args, 'namespace'),
|
|
53
|
+
sourceEnv: requireArg(args, 'source'),
|
|
54
|
+
targetEnv: requireArg(args, 'target'),
|
|
55
|
+
});
|
|
56
|
+
console.error(`Cloned ${written.length} parameter(s):\n${written.join('\n')}`);
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
case 'delete': {
|
|
60
|
+
const deleted = await deleteSsmNamespace({
|
|
61
|
+
namespace: requireArg(args, 'namespace'),
|
|
62
|
+
env: requireArg(args, 'env'),
|
|
63
|
+
});
|
|
64
|
+
console.error(`Deleted ${deleted.length} parameter(s):\n${deleted.join('\n')}`);
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
default:
|
|
68
|
+
console.error(USAGE);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
main().catch((err) => {
|
|
73
|
+
console.error(err);
|
|
74
|
+
process.exitCode = 1;
|
|
75
|
+
});
|
|
76
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,GAC/B,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,kBAAkB,GAInB,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export interface SsmConfigOptions {
|
|
2
|
+
/** Top-level SSM prefix, e.g. 'btfp'. */
|
|
3
|
+
namespace: string;
|
|
4
|
+
/** Any string — 'dev', 'prod', 'pr-123', a branch name. Not a fixed enum, so ephemeral stacks need no code changes. */
|
|
5
|
+
env: string;
|
|
6
|
+
region?: string;
|
|
7
|
+
/** Also merge in /{namespace}/shared/*, env-specific wins on key collision. Default true. */
|
|
8
|
+
includeShared?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Loads config for one namespace/env, merging /{namespace}/shared/* first
|
|
12
|
+
* and then /{namespace}/{env}/* on top (env wins on collision). Returns {}
|
|
13
|
+
* for an environment that hasn't been provisioned yet — never throws for
|
|
14
|
+
* that case — so a brand-new ephemeral stack still boots (degraded/
|
|
15
|
+
* placeholder) instead of crashing.
|
|
16
|
+
*/
|
|
17
|
+
export declare function loadSsmConfig(options: SsmConfigOptions): Promise<Record<string, string>>;
|
|
18
|
+
/**
|
|
19
|
+
* Writes each non-empty value to /{namespace}/{env}/{key} as a SecureString.
|
|
20
|
+
* Empty/undefined values are skipped (mirrors "don't push a placeholder").
|
|
21
|
+
* Returns the parameter names actually written.
|
|
22
|
+
*/
|
|
23
|
+
export declare function pushSsmConfig(options: SsmConfigOptions, values: Record<string, string | undefined>): Promise<string[]>;
|
|
24
|
+
export interface CloneSsmNamespaceOptions {
|
|
25
|
+
namespace: string;
|
|
26
|
+
sourceEnv: string;
|
|
27
|
+
targetEnv: string;
|
|
28
|
+
region?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The ephemeral-stack bootstrap primitive: copies every parameter from
|
|
32
|
+
* /{namespace}/{sourceEnv}/* to /{namespace}/{targetEnv}/* — e.g. spin up
|
|
33
|
+
* "pr-123" pre-populated from "dev"'s values. Idempotent (Overwrite: true).
|
|
34
|
+
*/
|
|
35
|
+
export declare function cloneSsmNamespace(options: CloneSsmNamespaceOptions): Promise<string[]>;
|
|
36
|
+
export interface DeleteSsmNamespaceOptions {
|
|
37
|
+
namespace: string;
|
|
38
|
+
env: string;
|
|
39
|
+
region?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The ephemeral-stack teardown primitive: deletes every parameter under
|
|
43
|
+
* /{namespace}/{env}/* — call when a PR closes / a preview stack is
|
|
44
|
+
* destroyed, so its secrets don't linger indefinitely.
|
|
45
|
+
*
|
|
46
|
+
* Confirmed empirically: SSM's GetParametersByPath can lag a few seconds
|
|
47
|
+
* behind a delete — a loadSsmConfig call immediately after this resolves
|
|
48
|
+
* can still show the just-deleted values before catching up. Don't chain
|
|
49
|
+
* "delete, then immediately verify empty" in a script without a short wait;
|
|
50
|
+
* a teardown pipeline that deletes and moves on (the normal case) is fine.
|
|
51
|
+
*/
|
|
52
|
+
export declare function deleteSsmNamespace(options: DeleteSsmNamespaceOptions): Promise<string[]>;
|
|
53
|
+
//# sourceMappingURL=ssm-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssm-config.d.ts","sourceRoot":"","sources":["../src/ssm-config.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,gBAAgB;IAC/B,yCAAyC;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,uHAAuH;IACvH,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6FAA6F;IAC7F,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAmDD;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAe9F;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GACzC,OAAO,CAAC,MAAM,EAAE,CAAC,CAanB;AAED,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAqB5F;AAED,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAc9F"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { GetParametersByPathCommand, PutParameterCommand, DeleteParametersCommand, SSMClient, } from '@aws-sdk/client-ssm';
|
|
2
|
+
/** SSM's DeleteParameters caps at 10 names per call. */
|
|
3
|
+
const DELETE_BATCH_SIZE = 10;
|
|
4
|
+
function resolveRegion(region) {
|
|
5
|
+
return region ?? process.env.AWS_REGION ?? 'us-east-1';
|
|
6
|
+
}
|
|
7
|
+
function leafName(parameterName) {
|
|
8
|
+
return parameterName.split('/').pop() ?? parameterName;
|
|
9
|
+
}
|
|
10
|
+
function toLeafMap(params) {
|
|
11
|
+
return Object.fromEntries(params.map((p) => [leafName(p.name), p.value]));
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Lists every parameter under `path`, decrypted. Returns [] for a path with
|
|
15
|
+
* no parameters at all — GetParametersByPath never throws for an empty
|
|
16
|
+
* result, unlike GetParameter for a single missing name — which is exactly
|
|
17
|
+
* what makes an unprovisioned/ephemeral environment degrade gracefully
|
|
18
|
+
* instead of failing to boot.
|
|
19
|
+
*/
|
|
20
|
+
async function listParametersUnderPath(client, path) {
|
|
21
|
+
const results = [];
|
|
22
|
+
let nextToken;
|
|
23
|
+
do {
|
|
24
|
+
const response = await client.send(new GetParametersByPathCommand({
|
|
25
|
+
Path: path,
|
|
26
|
+
Recursive: true,
|
|
27
|
+
WithDecryption: true,
|
|
28
|
+
NextToken: nextToken,
|
|
29
|
+
}));
|
|
30
|
+
for (const param of response.Parameters ?? []) {
|
|
31
|
+
if (param.Name && param.Value !== undefined) {
|
|
32
|
+
results.push({ name: param.Name, value: param.Value });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
nextToken = response.NextToken;
|
|
36
|
+
} while (nextToken);
|
|
37
|
+
return results;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Loads config for one namespace/env, merging /{namespace}/shared/* first
|
|
41
|
+
* and then /{namespace}/{env}/* on top (env wins on collision). Returns {}
|
|
42
|
+
* for an environment that hasn't been provisioned yet — never throws for
|
|
43
|
+
* that case — so a brand-new ephemeral stack still boots (degraded/
|
|
44
|
+
* placeholder) instead of crashing.
|
|
45
|
+
*/
|
|
46
|
+
export async function loadSsmConfig(options) {
|
|
47
|
+
const client = new SSMClient({ region: resolveRegion(options.region) });
|
|
48
|
+
const merged = {};
|
|
49
|
+
if (options.includeShared ?? true) {
|
|
50
|
+
Object.assign(merged, toLeafMap(await listParametersUnderPath(client, `/${options.namespace}/shared/`)));
|
|
51
|
+
}
|
|
52
|
+
Object.assign(merged, toLeafMap(await listParametersUnderPath(client, `/${options.namespace}/${options.env}/`)));
|
|
53
|
+
return merged;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Writes each non-empty value to /{namespace}/{env}/{key} as a SecureString.
|
|
57
|
+
* Empty/undefined values are skipped (mirrors "don't push a placeholder").
|
|
58
|
+
* Returns the parameter names actually written.
|
|
59
|
+
*/
|
|
60
|
+
export async function pushSsmConfig(options, values) {
|
|
61
|
+
const client = new SSMClient({ region: resolveRegion(options.region) });
|
|
62
|
+
const written = [];
|
|
63
|
+
for (const [key, value] of Object.entries(values)) {
|
|
64
|
+
if (!value)
|
|
65
|
+
continue;
|
|
66
|
+
const name = `/${options.namespace}/${options.env}/${key}`;
|
|
67
|
+
await client.send(new PutParameterCommand({ Name: name, Value: value, Type: 'SecureString', Overwrite: true }));
|
|
68
|
+
written.push(name);
|
|
69
|
+
}
|
|
70
|
+
return written;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The ephemeral-stack bootstrap primitive: copies every parameter from
|
|
74
|
+
* /{namespace}/{sourceEnv}/* to /{namespace}/{targetEnv}/* — e.g. spin up
|
|
75
|
+
* "pr-123" pre-populated from "dev"'s values. Idempotent (Overwrite: true).
|
|
76
|
+
*/
|
|
77
|
+
export async function cloneSsmNamespace(options) {
|
|
78
|
+
const client = new SSMClient({ region: resolveRegion(options.region) });
|
|
79
|
+
const sourceParams = await listParametersUnderPath(client, `/${options.namespace}/${options.sourceEnv}/`);
|
|
80
|
+
const written = [];
|
|
81
|
+
for (const param of sourceParams) {
|
|
82
|
+
const targetName = `/${options.namespace}/${options.targetEnv}/${leafName(param.name)}`;
|
|
83
|
+
await client.send(new PutParameterCommand({
|
|
84
|
+
Name: targetName,
|
|
85
|
+
Value: param.value,
|
|
86
|
+
Type: 'SecureString',
|
|
87
|
+
Overwrite: true,
|
|
88
|
+
}));
|
|
89
|
+
written.push(targetName);
|
|
90
|
+
}
|
|
91
|
+
return written;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The ephemeral-stack teardown primitive: deletes every parameter under
|
|
95
|
+
* /{namespace}/{env}/* — call when a PR closes / a preview stack is
|
|
96
|
+
* destroyed, so its secrets don't linger indefinitely.
|
|
97
|
+
*
|
|
98
|
+
* Confirmed empirically: SSM's GetParametersByPath can lag a few seconds
|
|
99
|
+
* behind a delete — a loadSsmConfig call immediately after this resolves
|
|
100
|
+
* can still show the just-deleted values before catching up. Don't chain
|
|
101
|
+
* "delete, then immediately verify empty" in a script without a short wait;
|
|
102
|
+
* a teardown pipeline that deletes and moves on (the normal case) is fine.
|
|
103
|
+
*/
|
|
104
|
+
export async function deleteSsmNamespace(options) {
|
|
105
|
+
const client = new SSMClient({ region: resolveRegion(options.region) });
|
|
106
|
+
const path = `/${options.namespace}/${options.env}/`;
|
|
107
|
+
const params = await listParametersUnderPath(client, path);
|
|
108
|
+
if (params.length === 0)
|
|
109
|
+
return [];
|
|
110
|
+
const names = params.map((p) => p.name);
|
|
111
|
+
const deleted = [];
|
|
112
|
+
for (let i = 0; i < names.length; i += DELETE_BATCH_SIZE) {
|
|
113
|
+
const batch = names.slice(i, i + DELETE_BATCH_SIZE);
|
|
114
|
+
await client.send(new DeleteParametersCommand({ Names: batch }));
|
|
115
|
+
deleted.push(...batch);
|
|
116
|
+
}
|
|
117
|
+
return deleted;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=ssm-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssm-config.js","sourceRoot":"","sources":["../src/ssm-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssm-config.spec.d.ts","sourceRoot":"","sources":["../src/ssm-config.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it } from 'vitest';
|
|
2
|
+
import { mockClient } from 'aws-sdk-client-mock';
|
|
3
|
+
import { SSMClient, GetParametersByPathCommand, PutParameterCommand, DeleteParametersCommand, } from '@aws-sdk/client-ssm';
|
|
4
|
+
import { loadSsmConfig, pushSsmConfig, cloneSsmNamespace, deleteSsmNamespace, } from './ssm-config.js';
|
|
5
|
+
const ssmMock = mockClient(SSMClient);
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
ssmMock.reset();
|
|
8
|
+
});
|
|
9
|
+
describe('loadSsmConfig', () => {
|
|
10
|
+
it('merges shared params first, then env-specific overrides on collision', async () => {
|
|
11
|
+
ssmMock
|
|
12
|
+
.on(GetParametersByPathCommand, { Path: '/myapp/shared/', Recursive: true })
|
|
13
|
+
.resolves({
|
|
14
|
+
Parameters: [
|
|
15
|
+
{ Name: '/myapp/shared/brave-search-api-key', Value: 'shared-brave-key' },
|
|
16
|
+
{ Name: '/myapp/shared/jwt-secret', Value: 'shared-jwt' },
|
|
17
|
+
],
|
|
18
|
+
})
|
|
19
|
+
.on(GetParametersByPathCommand, { Path: '/myapp/dev/', Recursive: true })
|
|
20
|
+
.resolves({
|
|
21
|
+
Parameters: [{ Name: '/myapp/dev/jwt-secret', Value: 'dev-jwt' }],
|
|
22
|
+
});
|
|
23
|
+
const result = await loadSsmConfig({ namespace: 'myapp', env: 'dev' });
|
|
24
|
+
expect(result).toEqual({
|
|
25
|
+
'brave-search-api-key': 'shared-brave-key',
|
|
26
|
+
'jwt-secret': 'dev-jwt', // env-specific wins over shared
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
it('returns {} for an unprovisioned/ephemeral environment instead of throwing', async () => {
|
|
30
|
+
ssmMock.on(GetParametersByPathCommand).resolves({ Parameters: [] });
|
|
31
|
+
const result = await loadSsmConfig({ namespace: 'myapp', env: 'pr-999', includeShared: false });
|
|
32
|
+
expect(result).toEqual({});
|
|
33
|
+
});
|
|
34
|
+
it('skips the shared lookup when includeShared is false', async () => {
|
|
35
|
+
ssmMock
|
|
36
|
+
.on(GetParametersByPathCommand, { Path: '/myapp/dev/', Recursive: true })
|
|
37
|
+
.resolves({ Parameters: [{ Name: '/myapp/dev/jwt-secret', Value: 'dev-jwt' }] });
|
|
38
|
+
const result = await loadSsmConfig({ namespace: 'myapp', env: 'dev', includeShared: false });
|
|
39
|
+
expect(result).toEqual({ 'jwt-secret': 'dev-jwt' });
|
|
40
|
+
expect(ssmMock.commandCalls(GetParametersByPathCommand, { Path: '/myapp/shared/' })).toHaveLength(0);
|
|
41
|
+
});
|
|
42
|
+
it('follows NextToken pagination', async () => {
|
|
43
|
+
ssmMock
|
|
44
|
+
.on(GetParametersByPathCommand, { Path: '/myapp/dev/', Recursive: true })
|
|
45
|
+
.resolvesOnce({
|
|
46
|
+
Parameters: [{ Name: '/myapp/dev/key-a', Value: 'a' }],
|
|
47
|
+
NextToken: 'page-2',
|
|
48
|
+
})
|
|
49
|
+
.resolves({
|
|
50
|
+
Parameters: [{ Name: '/myapp/dev/key-b', Value: 'b' }],
|
|
51
|
+
});
|
|
52
|
+
const result = await loadSsmConfig({ namespace: 'myapp', env: 'dev', includeShared: false });
|
|
53
|
+
expect(result).toEqual({ 'key-a': 'a', 'key-b': 'b' });
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
describe('pushSsmConfig', () => {
|
|
57
|
+
it('writes each non-empty value as a SecureString under the env path', async () => {
|
|
58
|
+
ssmMock.on(PutParameterCommand).resolves({});
|
|
59
|
+
const written = await pushSsmConfig({ namespace: 'myapp', env: 'dev' }, { 'jwt-secret': 'real-value', 'unset-key': undefined, 'empty-key': '' });
|
|
60
|
+
expect(written).toEqual(['/myapp/dev/jwt-secret']);
|
|
61
|
+
expect(ssmMock.commandCalls(PutParameterCommand)).toHaveLength(1);
|
|
62
|
+
expect(ssmMock.commandCalls(PutParameterCommand)[0]?.args[0].input).toMatchObject({
|
|
63
|
+
Name: '/myapp/dev/jwt-secret',
|
|
64
|
+
Value: 'real-value',
|
|
65
|
+
Type: 'SecureString',
|
|
66
|
+
Overwrite: true,
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
describe('cloneSsmNamespace', () => {
|
|
71
|
+
it('copies every source-env parameter to the target env', async () => {
|
|
72
|
+
ssmMock.on(GetParametersByPathCommand, { Path: '/myapp/dev/', Recursive: true }).resolves({
|
|
73
|
+
Parameters: [
|
|
74
|
+
{ Name: '/myapp/dev/jwt-secret', Value: 'dev-jwt' },
|
|
75
|
+
{ Name: '/myapp/dev/basic-auth-user', Value: 'admin' },
|
|
76
|
+
],
|
|
77
|
+
});
|
|
78
|
+
ssmMock.on(PutParameterCommand).resolves({});
|
|
79
|
+
const written = await cloneSsmNamespace({
|
|
80
|
+
namespace: 'myapp',
|
|
81
|
+
sourceEnv: 'dev',
|
|
82
|
+
targetEnv: 'pr-123',
|
|
83
|
+
});
|
|
84
|
+
expect(written.sort()).toEqual(['/myapp/pr-123/jwt-secret', '/myapp/pr-123/basic-auth-user'].sort());
|
|
85
|
+
expect(ssmMock.commandCalls(PutParameterCommand)).toHaveLength(2);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
describe('deleteSsmNamespace', () => {
|
|
89
|
+
it('returns [] without calling DeleteParameters when nothing exists', async () => {
|
|
90
|
+
ssmMock.on(GetParametersByPathCommand).resolves({ Parameters: [] });
|
|
91
|
+
const deleted = await deleteSsmNamespace({ namespace: 'myapp', env: 'pr-123' });
|
|
92
|
+
expect(deleted).toEqual([]);
|
|
93
|
+
expect(ssmMock.commandCalls(DeleteParametersCommand)).toHaveLength(0);
|
|
94
|
+
});
|
|
95
|
+
it('batches deletes at 10 names per call', async () => {
|
|
96
|
+
const names = Array.from({ length: 23 }, (_, i) => `/myapp/pr-123/key-${i}`);
|
|
97
|
+
ssmMock
|
|
98
|
+
.on(GetParametersByPathCommand, { Path: '/myapp/pr-123/', Recursive: true })
|
|
99
|
+
.resolves({ Parameters: names.map((name) => ({ Name: name, Value: 'v' })) });
|
|
100
|
+
ssmMock.on(DeleteParametersCommand).resolves({});
|
|
101
|
+
const deleted = await deleteSsmNamespace({ namespace: 'myapp', env: 'pr-123' });
|
|
102
|
+
expect(deleted).toHaveLength(23);
|
|
103
|
+
const calls = ssmMock.commandCalls(DeleteParametersCommand);
|
|
104
|
+
expect(calls).toHaveLength(3); // 10 + 10 + 3
|
|
105
|
+
expect(calls[0]?.args[0].input.Names).toHaveLength(10);
|
|
106
|
+
expect(calls[2]?.args[0].input.Names).toHaveLength(3);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
//# sourceMappingURL=ssm-config.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssm-config.spec.js","sourceRoot":"","sources":["../src/ssm-config.spec.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bubltec/mycota-config",
|
|
3
|
+
"version": "0.1.0-dev.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"bin": {
|
|
14
|
+
"mycota-config": "./dist/cli.js"
|
|
15
|
+
},
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"default": "./dist/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@aws-sdk/client-ssm": "^3.716.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/node": "^22.10.0",
|
|
27
|
+
"aws-sdk-client-mock": "^4.1.0",
|
|
28
|
+
"typescript": "^5.8.0",
|
|
29
|
+
"vitest": "^2.1.0"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsc -b",
|
|
33
|
+
"typecheck": "tsc -b --noEmit",
|
|
34
|
+
"test": "vitest run"
|
|
35
|
+
}
|
|
36
|
+
}
|