@openhi/constructs 0.0.152 → 0.0.154
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/lib/{chunk-SXYY5WHG.mjs → chunk-ZVDVKCNC.mjs} +83 -15
- package/lib/chunk-ZVDVKCNC.mjs.map +1 -0
- package/lib/index.js +27 -1
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +27 -1
- package/lib/index.mjs.map +1 -1
- package/lib/seed-demo-data.handler.d.mts +45 -10
- package/lib/seed-demo-data.handler.d.ts +45 -10
- package/lib/seed-demo-data.handler.js +82 -15
- package/lib/seed-demo-data.handler.js.map +1 -1
- package/lib/seed-demo-data.handler.mjs +9 -3
- package/package.json +12 -12
- package/lib/chunk-SXYY5WHG.mjs.map +0 -1
|
@@ -97,13 +97,40 @@ declare const seedDemoGraph: (params: {
|
|
|
97
97
|
*/
|
|
98
98
|
declare const runSeedDemoData: (event: SeedDemoDataEvent, deps: SeedDemoDataDependencies, devUsers: ReadonlyArray<DemoDevUser>) => Promise<void>;
|
|
99
99
|
/**
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
100
|
+
* SSM parameter-path prefix that hosts every seeded dev user's
|
|
101
|
+
* password. The full path for a single user is
|
|
102
|
+
* `${SEED_USER_PASSWORD_PARAMETER_PREFIX}<email_safe>/password`
|
|
103
|
+
* where `<email_safe>` is `<user>_at_<domain>` (see
|
|
104
|
+
* {@link emailToSsmPath}). The trailing `/password` segment leaves
|
|
105
|
+
* room for additional per-user parameters under the same email
|
|
106
|
+
* prefix in future phases without renaming the existing entries.
|
|
105
107
|
*/
|
|
106
|
-
declare const
|
|
108
|
+
declare const SEED_USER_PASSWORD_PARAMETER_PREFIX = "/openhi/seed/users/";
|
|
109
|
+
/**
|
|
110
|
+
* Map an email address to its canonical SSM parameter path. The
|
|
111
|
+
* `@` separator is replaced with the literal sentinel `_at_` so
|
|
112
|
+
* the resulting path is a single SSM-legal name. Throws when the
|
|
113
|
+
* email is empty, missing exactly one `@`, or contains characters
|
|
114
|
+
* that would produce an invalid SSM path.
|
|
115
|
+
*
|
|
116
|
+
* Example: `alice@codedrifters.com` →
|
|
117
|
+
* `/openhi/seed/users/alice_at_codedrifters.com/password`.
|
|
118
|
+
*/
|
|
119
|
+
declare const emailToSsmPath: (email: string) => string;
|
|
120
|
+
/**
|
|
121
|
+
* Test seam: reset the module-scoped SSM client cache. Unit tests
|
|
122
|
+
* that swap in different mocks across `it` blocks call this in
|
|
123
|
+
* `beforeEach` so each test gets a fresh client instance.
|
|
124
|
+
*/
|
|
125
|
+
declare const __resetSsmClientForTests: () => void;
|
|
126
|
+
/**
|
|
127
|
+
* Read a seeded dev user's password from SSM Parameter Store. The
|
|
128
|
+
* parameter is expected to be a `SecureString` provisioned out of
|
|
129
|
+
* band by an operator (see the runbook in phase 3 of #1249). On
|
|
130
|
+
* `ParameterNotFound`, the error message includes the exact
|
|
131
|
+
* expected path so the operator can copy-paste-fix.
|
|
132
|
+
*/
|
|
133
|
+
declare const fetchSeedUserPassword: (email: string) => Promise<string>;
|
|
107
134
|
/**
|
|
108
135
|
* Production Cognito provisioner backed by the AWS SDK. Reads the
|
|
109
136
|
* user-pool id from the env var the lambda construct injects.
|
|
@@ -111,13 +138,21 @@ declare const devPasswordForEmail: (email: string) => string;
|
|
|
111
138
|
* Idempotency contract:
|
|
112
139
|
* - On first invocation, calls `AdminCreateUser` (with
|
|
113
140
|
* `MessageAction: SUPPRESS` so no invitation email fires) then
|
|
114
|
-
* `AdminSetUserPassword` (permanent
|
|
141
|
+
* `AdminSetUserPassword` (permanent, from the SSM-sourced
|
|
142
|
+
* value). Returns the new user's sub.
|
|
115
143
|
* - On subsequent invocations, `AdminCreateUser` throws
|
|
116
144
|
* `UsernameExistsException`; the provisioner catches it, calls
|
|
117
|
-
* `AdminGetUser` to read the existing user's sub, and
|
|
118
|
-
*
|
|
145
|
+
* `AdminGetUser` to read the existing user's sub, and **also
|
|
146
|
+
* re-applies the current SSM-sourced password** via
|
|
147
|
+
* `AdminSetUserPassword`. This is the rotation seam: operators
|
|
148
|
+
* update the SSM SecureString value and re-publish the seed
|
|
149
|
+
* event to push a fresh password down to Cognito.
|
|
150
|
+
*
|
|
151
|
+
* The SSM password is fetched once per email up-front so the new-
|
|
152
|
+
* user and rotation branches share the same value and at most one
|
|
153
|
+
* `GetParameter` call lands per `ensureUser` invocation.
|
|
119
154
|
*/
|
|
120
155
|
declare const productionCognitoProvisioner: () => CognitoProvisioner;
|
|
121
156
|
declare const handler: (event: SeedDemoDataEvent) => Promise<void>;
|
|
122
157
|
|
|
123
|
-
export { type CognitoProvisioner, SEED_DEMO_DATA_USER_POOL_ID_ENV_VAR, type SeedDemoDataDependencies,
|
|
158
|
+
export { type CognitoProvisioner, SEED_DEMO_DATA_USER_POOL_ID_ENV_VAR, SEED_USER_PASSWORD_PARAMETER_PREFIX, type SeedDemoDataDependencies, __resetSsmClientForTests, emailToSsmPath, fetchSeedUserPassword, handler, productionCognitoProvisioner, runSeedDemoData, seedDemoGraph };
|
|
@@ -97,13 +97,40 @@ declare const seedDemoGraph: (params: {
|
|
|
97
97
|
*/
|
|
98
98
|
declare const runSeedDemoData: (event: SeedDemoDataEvent, deps: SeedDemoDataDependencies, devUsers: ReadonlyArray<DemoDevUser>) => Promise<void>;
|
|
99
99
|
/**
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
100
|
+
* SSM parameter-path prefix that hosts every seeded dev user's
|
|
101
|
+
* password. The full path for a single user is
|
|
102
|
+
* `${SEED_USER_PASSWORD_PARAMETER_PREFIX}<email_safe>/password`
|
|
103
|
+
* where `<email_safe>` is `<user>_at_<domain>` (see
|
|
104
|
+
* {@link emailToSsmPath}). The trailing `/password` segment leaves
|
|
105
|
+
* room for additional per-user parameters under the same email
|
|
106
|
+
* prefix in future phases without renaming the existing entries.
|
|
105
107
|
*/
|
|
106
|
-
declare const
|
|
108
|
+
declare const SEED_USER_PASSWORD_PARAMETER_PREFIX = "/openhi/seed/users/";
|
|
109
|
+
/**
|
|
110
|
+
* Map an email address to its canonical SSM parameter path. The
|
|
111
|
+
* `@` separator is replaced with the literal sentinel `_at_` so
|
|
112
|
+
* the resulting path is a single SSM-legal name. Throws when the
|
|
113
|
+
* email is empty, missing exactly one `@`, or contains characters
|
|
114
|
+
* that would produce an invalid SSM path.
|
|
115
|
+
*
|
|
116
|
+
* Example: `alice@codedrifters.com` →
|
|
117
|
+
* `/openhi/seed/users/alice_at_codedrifters.com/password`.
|
|
118
|
+
*/
|
|
119
|
+
declare const emailToSsmPath: (email: string) => string;
|
|
120
|
+
/**
|
|
121
|
+
* Test seam: reset the module-scoped SSM client cache. Unit tests
|
|
122
|
+
* that swap in different mocks across `it` blocks call this in
|
|
123
|
+
* `beforeEach` so each test gets a fresh client instance.
|
|
124
|
+
*/
|
|
125
|
+
declare const __resetSsmClientForTests: () => void;
|
|
126
|
+
/**
|
|
127
|
+
* Read a seeded dev user's password from SSM Parameter Store. The
|
|
128
|
+
* parameter is expected to be a `SecureString` provisioned out of
|
|
129
|
+
* band by an operator (see the runbook in phase 3 of #1249). On
|
|
130
|
+
* `ParameterNotFound`, the error message includes the exact
|
|
131
|
+
* expected path so the operator can copy-paste-fix.
|
|
132
|
+
*/
|
|
133
|
+
declare const fetchSeedUserPassword: (email: string) => Promise<string>;
|
|
107
134
|
/**
|
|
108
135
|
* Production Cognito provisioner backed by the AWS SDK. Reads the
|
|
109
136
|
* user-pool id from the env var the lambda construct injects.
|
|
@@ -111,13 +138,21 @@ declare const devPasswordForEmail: (email: string) => string;
|
|
|
111
138
|
* Idempotency contract:
|
|
112
139
|
* - On first invocation, calls `AdminCreateUser` (with
|
|
113
140
|
* `MessageAction: SUPPRESS` so no invitation email fires) then
|
|
114
|
-
* `AdminSetUserPassword` (permanent
|
|
141
|
+
* `AdminSetUserPassword` (permanent, from the SSM-sourced
|
|
142
|
+
* value). Returns the new user's sub.
|
|
115
143
|
* - On subsequent invocations, `AdminCreateUser` throws
|
|
116
144
|
* `UsernameExistsException`; the provisioner catches it, calls
|
|
117
|
-
* `AdminGetUser` to read the existing user's sub, and
|
|
118
|
-
*
|
|
145
|
+
* `AdminGetUser` to read the existing user's sub, and **also
|
|
146
|
+
* re-applies the current SSM-sourced password** via
|
|
147
|
+
* `AdminSetUserPassword`. This is the rotation seam: operators
|
|
148
|
+
* update the SSM SecureString value and re-publish the seed
|
|
149
|
+
* event to push a fresh password down to Cognito.
|
|
150
|
+
*
|
|
151
|
+
* The SSM password is fetched once per email up-front so the new-
|
|
152
|
+
* user and rotation branches share the same value and at most one
|
|
153
|
+
* `GetParameter` call lands per `ensureUser` invocation.
|
|
119
154
|
*/
|
|
120
155
|
declare const productionCognitoProvisioner: () => CognitoProvisioner;
|
|
121
156
|
declare const handler: (event: SeedDemoDataEvent) => Promise<void>;
|
|
122
157
|
|
|
123
|
-
export { type CognitoProvisioner, SEED_DEMO_DATA_USER_POOL_ID_ENV_VAR, type SeedDemoDataDependencies,
|
|
158
|
+
export { type CognitoProvisioner, SEED_DEMO_DATA_USER_POOL_ID_ENV_VAR, SEED_USER_PASSWORD_PARAMETER_PREFIX, type SeedDemoDataDependencies, __resetSsmClientForTests, emailToSsmPath, fetchSeedUserPassword, handler, productionCognitoProvisioner, runSeedDemoData, seedDemoGraph };
|
|
@@ -707,16 +707,19 @@ var require_lib = __commonJS({
|
|
|
707
707
|
var seed_demo_data_handler_exports = {};
|
|
708
708
|
__export(seed_demo_data_handler_exports, {
|
|
709
709
|
SEED_DEMO_DATA_USER_POOL_ID_ENV_VAR: () => SEED_DEMO_DATA_USER_POOL_ID_ENV_VAR,
|
|
710
|
-
|
|
710
|
+
SEED_USER_PASSWORD_PARAMETER_PREFIX: () => SEED_USER_PASSWORD_PARAMETER_PREFIX,
|
|
711
|
+
__resetSsmClientForTests: () => __resetSsmClientForTests,
|
|
712
|
+
emailToSsmPath: () => emailToSsmPath,
|
|
713
|
+
fetchSeedUserPassword: () => fetchSeedUserPassword,
|
|
711
714
|
handler: () => handler,
|
|
712
715
|
productionCognitoProvisioner: () => productionCognitoProvisioner,
|
|
713
716
|
runSeedDemoData: () => runSeedDemoData,
|
|
714
717
|
seedDemoGraph: () => seedDemoGraph
|
|
715
718
|
});
|
|
716
719
|
module.exports = __toCommonJS(seed_demo_data_handler_exports);
|
|
717
|
-
var import_node_crypto = require("crypto");
|
|
718
720
|
var import_client_cognito_identity_provider = require("@aws-sdk/client-cognito-identity-provider");
|
|
719
721
|
var import_client_dynamodb2 = require("@aws-sdk/client-dynamodb");
|
|
722
|
+
var import_client_ssm = require("@aws-sdk/client-ssm");
|
|
720
723
|
var import_types12 = require("@openhi/types");
|
|
721
724
|
var import_workflows2 = __toESM(require_lib());
|
|
722
725
|
|
|
@@ -5412,10 +5415,66 @@ var runSeedDemoData = async (event, deps, devUsers) => {
|
|
|
5412
5415
|
throw err;
|
|
5413
5416
|
}
|
|
5414
5417
|
};
|
|
5415
|
-
var
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5418
|
+
var SEED_USER_PASSWORD_PARAMETER_PREFIX = "/openhi/seed/users/";
|
|
5419
|
+
var SSM_PATH_SEGMENT = /^[A-Za-z0-9_.-]+$/;
|
|
5420
|
+
var emailToSsmPath = (email) => {
|
|
5421
|
+
if (typeof email !== "string" || email.length === 0) {
|
|
5422
|
+
throw new Error(
|
|
5423
|
+
`emailToSsmPath: email must be a non-empty string (received "${String(email)}").`
|
|
5424
|
+
);
|
|
5425
|
+
}
|
|
5426
|
+
const atIdx = email.indexOf("@");
|
|
5427
|
+
if (atIdx === -1 || atIdx !== email.lastIndexOf("@")) {
|
|
5428
|
+
throw new Error(
|
|
5429
|
+
`emailToSsmPath: email "${email}" must contain exactly one "@" character.`
|
|
5430
|
+
);
|
|
5431
|
+
}
|
|
5432
|
+
const localPart = email.slice(0, atIdx);
|
|
5433
|
+
const domainPart = email.slice(atIdx + 1);
|
|
5434
|
+
if (localPart.length === 0 || domainPart.length === 0) {
|
|
5435
|
+
throw new Error(
|
|
5436
|
+
`emailToSsmPath: email "${email}" must have a non-empty local-part and domain.`
|
|
5437
|
+
);
|
|
5438
|
+
}
|
|
5439
|
+
if (!SSM_PATH_SEGMENT.test(localPart) || !SSM_PATH_SEGMENT.test(domainPart)) {
|
|
5440
|
+
throw new Error(
|
|
5441
|
+
`emailToSsmPath: email "${email}" contains characters that would produce an invalid SSM parameter path (only A-Z, a-z, 0-9, '.', '-', and '_' are allowed).`
|
|
5442
|
+
);
|
|
5443
|
+
}
|
|
5444
|
+
return `${SEED_USER_PASSWORD_PARAMETER_PREFIX}${localPart}_at_${domainPart}/password`;
|
|
5445
|
+
};
|
|
5446
|
+
var cachedSsmClient;
|
|
5447
|
+
var getSsmClient = () => {
|
|
5448
|
+
if (!cachedSsmClient) {
|
|
5449
|
+
cachedSsmClient = new import_client_ssm.SSMClient({});
|
|
5450
|
+
}
|
|
5451
|
+
return cachedSsmClient;
|
|
5452
|
+
};
|
|
5453
|
+
var __resetSsmClientForTests = () => {
|
|
5454
|
+
cachedSsmClient = void 0;
|
|
5455
|
+
};
|
|
5456
|
+
var fetchSeedUserPassword = async (email) => {
|
|
5457
|
+
const path = emailToSsmPath(email);
|
|
5458
|
+
const client = getSsmClient();
|
|
5459
|
+
try {
|
|
5460
|
+
const result = await client.send(
|
|
5461
|
+
new import_client_ssm.GetParameterCommand({ Name: path, WithDecryption: true })
|
|
5462
|
+
);
|
|
5463
|
+
const value = result.Parameter?.Value;
|
|
5464
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
5465
|
+
throw new Error(
|
|
5466
|
+
`fetchSeedUserPassword: SSM parameter "${path}" returned an empty value.`
|
|
5467
|
+
);
|
|
5468
|
+
}
|
|
5469
|
+
return value;
|
|
5470
|
+
} catch (err) {
|
|
5471
|
+
if (err instanceof import_client_ssm.ParameterNotFound) {
|
|
5472
|
+
throw new Error(
|
|
5473
|
+
`fetchSeedUserPassword: SSM parameter "${path}" not found. Provision a SecureString at "${path}" with the dev user's password before re-running seed-demo-data.`
|
|
5474
|
+
);
|
|
5475
|
+
}
|
|
5476
|
+
throw err;
|
|
5477
|
+
}
|
|
5419
5478
|
};
|
|
5420
5479
|
var productionCognitoProvisioner = () => {
|
|
5421
5480
|
const client = new import_client_cognito_identity_provider.CognitoIdentityProviderClient({});
|
|
@@ -5433,8 +5492,19 @@ var productionCognitoProvisioner = () => {
|
|
|
5433
5492
|
}
|
|
5434
5493
|
return void 0;
|
|
5435
5494
|
};
|
|
5495
|
+
const setPassword = async (email, password) => {
|
|
5496
|
+
await client.send(
|
|
5497
|
+
new import_client_cognito_identity_provider.AdminSetUserPasswordCommand({
|
|
5498
|
+
UserPoolId: userPoolId,
|
|
5499
|
+
Username: email,
|
|
5500
|
+
Password: password,
|
|
5501
|
+
Permanent: true
|
|
5502
|
+
})
|
|
5503
|
+
);
|
|
5504
|
+
};
|
|
5436
5505
|
return {
|
|
5437
5506
|
ensureUser: async (email) => {
|
|
5507
|
+
const password = await fetchSeedUserPassword(email);
|
|
5438
5508
|
try {
|
|
5439
5509
|
const created = await client.send(
|
|
5440
5510
|
new import_client_cognito_identity_provider.AdminCreateUserCommand({
|
|
@@ -5447,14 +5517,7 @@ var productionCognitoProvisioner = () => {
|
|
|
5447
5517
|
]
|
|
5448
5518
|
})
|
|
5449
5519
|
);
|
|
5450
|
-
await
|
|
5451
|
-
new import_client_cognito_identity_provider.AdminSetUserPasswordCommand({
|
|
5452
|
-
UserPoolId: userPoolId,
|
|
5453
|
-
Username: email,
|
|
5454
|
-
Password: devPasswordForEmail(email),
|
|
5455
|
-
Permanent: true
|
|
5456
|
-
})
|
|
5457
|
-
);
|
|
5520
|
+
await setPassword(email, password);
|
|
5458
5521
|
const sub = subFromAttributes(created.User?.Attributes);
|
|
5459
5522
|
if (!sub) {
|
|
5460
5523
|
throw new Error(
|
|
@@ -5464,6 +5527,7 @@ var productionCognitoProvisioner = () => {
|
|
|
5464
5527
|
return sub;
|
|
5465
5528
|
} catch (err) {
|
|
5466
5529
|
if (err instanceof import_client_cognito_identity_provider.UsernameExistsException) {
|
|
5530
|
+
await setPassword(email, password);
|
|
5467
5531
|
const got = await client.send(
|
|
5468
5532
|
new import_client_cognito_identity_provider.AdminGetUserCommand({
|
|
5469
5533
|
UserPoolId: userPoolId,
|
|
@@ -5497,7 +5561,10 @@ var handler = async (event) => runSeedDemoData(event, productionDependencies(),
|
|
|
5497
5561
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5498
5562
|
0 && (module.exports = {
|
|
5499
5563
|
SEED_DEMO_DATA_USER_POOL_ID_ENV_VAR,
|
|
5500
|
-
|
|
5564
|
+
SEED_USER_PASSWORD_PARAMETER_PREFIX,
|
|
5565
|
+
__resetSsmClientForTests,
|
|
5566
|
+
emailToSsmPath,
|
|
5567
|
+
fetchSeedUserPassword,
|
|
5501
5568
|
handler,
|
|
5502
5569
|
productionCognitoProvisioner,
|
|
5503
5570
|
runSeedDemoData,
|