@liflig/load-secrets 1.0.3 → 1.0.5

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.
@@ -0,0 +1,21 @@
1
+ import chalk from "chalk";
2
+ export declare function createReporter(argv: Record<string, unknown>): CLIReporter;
3
+ export declare class CLIReporter {
4
+ constructor(opts?: {
5
+ nonInteractive?: boolean;
6
+ verbose?: boolean;
7
+ });
8
+ stdout: NodeJS.WriteStream & {
9
+ fd: 1;
10
+ };
11
+ stderr: NodeJS.WriteStream & {
12
+ fd: 2;
13
+ };
14
+ nonInteractive: boolean;
15
+ isVerbose: boolean;
16
+ format: typeof chalk;
17
+ error(msg: string): void;
18
+ log(msg: string): void;
19
+ warn(msg: string): void;
20
+ info(msg: string): void;
21
+ }
@@ -0,0 +1,41 @@
1
+ import chalk from "chalk";
2
+ import readline from "readline";
3
+ const CLEAR_WHOLE_LINE = 0;
4
+ export function createReporter(argv) {
5
+ return new CLIReporter({
6
+ verbose: !!argv.verbose,
7
+ nonInteractive: !!argv.nonInteractive,
8
+ });
9
+ }
10
+ function clearLine(stdout) {
11
+ readline.clearLine(stdout, CLEAR_WHOLE_LINE);
12
+ readline.cursorTo(stdout, 0);
13
+ }
14
+ export class CLIReporter {
15
+ constructor(opts = {}) {
16
+ this.nonInteractive = !!opts.nonInteractive;
17
+ this.isVerbose = !!opts.verbose;
18
+ }
19
+ stdout = process.stdout;
20
+ stderr = process.stderr;
21
+ nonInteractive;
22
+ isVerbose;
23
+ format = chalk;
24
+ error(msg) {
25
+ clearLine(this.stderr);
26
+ this.stderr.write(`${this.format.red("error")} ${msg}\n`);
27
+ }
28
+ log(msg) {
29
+ clearLine(this.stdout);
30
+ this.stdout.write(`${msg}\n`);
31
+ }
32
+ warn(msg) {
33
+ clearLine(this.stderr);
34
+ this.stderr.write(`${this.format.yellow("warning")} ${msg}\n`);
35
+ }
36
+ info(msg) {
37
+ clearLine(this.stdout);
38
+ this.stdout.write(`${this.format.blue("info")} ${msg}\n`);
39
+ }
40
+ }
41
+ //# sourceMappingURL=reporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporter.js","sourceRoot":"","sources":["../../src/cli/reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,QAAQ,MAAM,UAAU,CAAC;AAEhC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAE3B,MAAM,UAAU,cAAc,CAAC,IAA6B;IAC1D,OAAO,IAAI,WAAW,CAAC;QACrB,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO;QACvB,cAAc,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc;KACtC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,SAAS,CAAC,MAA0B;IAC3C,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC7C,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,OAAO,WAAW;IACtB,YACE,OAGI,EAAE;QAEN,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC;QAC5C,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;IAClC,CAAC;IAEM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IACxB,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IACxB,cAAc,CAAU;IACxB,SAAS,CAAU;IACnB,MAAM,GAAiB,KAAK,CAAC;IAE7B,KAAK,CAAC,GAAW;QACtB,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IAC5D,CAAC;IAEM,GAAG,CAAC,GAAW;QACpB,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;IAChC,CAAC;IAEM,IAAI,CAAC,GAAW;QACrB,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IACjE,CAAC;IAEM,IAAI,CAAC,GAAW;QACrB,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IAC5D,CAAC;CACF"}
package/lib/index.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * as loadSecrets from "./load-secrets";
package/lib/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export * as loadSecrets from "./load-secrets";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,WAAW,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { loadSecretsCli } from "./load-secrets";
2
+ export type { JsonSecret, Secret, SecretGroup } from "./types";
@@ -0,0 +1,2 @@
1
+ export { loadSecretsCli } from "./load-secrets";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/load-secrets/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { SecretGroup } from "./types";
2
+ /**
3
+ * Load secrets interactively into Secrets Manager.
4
+ */
5
+ export declare function loadSecretsCli(props: {
6
+ secretGroups: SecretGroup[];
7
+ }): void;
@@ -0,0 +1,314 @@
1
+ import { CreateSecretCommand, DescribeSecretCommand, GetSecretValueCommand, PutSecretValueCommand, RemoveRegionsFromReplicationCommand, ReplicateSecretToRegionsCommand, ResourceNotFoundException, RestoreSecretCommand, SecretsManagerClient, TagResourceCommand, UntagResourceCommand, } from "@aws-sdk/client-secrets-manager";
2
+ import { GetCallerIdentityCommand, STSClient } from "@aws-sdk/client-sts";
3
+ import { read } from "read";
4
+ import { createReporter } from "../cli/reporter";
5
+ class LoadSecrets {
6
+ smClientForRegions = {};
7
+ stsClient;
8
+ reporter;
9
+ silent;
10
+ constructor(props) {
11
+ this.stsClient = new STSClient({
12
+ region: "eu-west-1",
13
+ });
14
+ this.reporter = props.reporter;
15
+ this.silent = props.silent;
16
+ }
17
+ getSmClient(region) {
18
+ if (!this.smClientForRegions[region]) {
19
+ this.smClientForRegions[region] = new SecretsManagerClient({
20
+ region,
21
+ });
22
+ }
23
+ return this.smClientForRegions[region];
24
+ }
25
+ async getInput(options) {
26
+ return read(options);
27
+ }
28
+ async getSecretDetails(client, secretId) {
29
+ try {
30
+ return await client.send(new DescribeSecretCommand({ SecretId: secretId }));
31
+ }
32
+ catch (e) {
33
+ if (e instanceof ResourceNotFoundException) {
34
+ return null;
35
+ }
36
+ throw e;
37
+ }
38
+ }
39
+ async handleStringUpdate() {
40
+ return await this.getInput({
41
+ prompt: "Enter value (Ctrl+C to abort): ",
42
+ silent: this.silent,
43
+ });
44
+ }
45
+ async handleJsonUpdate(secret) {
46
+ this.reporter.log("The secret is of type JSON with these expected fields:");
47
+ for (const field of secret.fields) {
48
+ const key = typeof field === "string" ? field : field.key;
49
+ const desc = typeof field === "string"
50
+ ? ""
51
+ : field.description
52
+ ? ` (${field.description})`
53
+ : "";
54
+ this.reporter.log(` - ${key}${desc}`);
55
+ }
56
+ this.reporter.log("");
57
+ // TODO: Ability to specify full json value as one line.
58
+ const collectedValues = {};
59
+ for (const field of secret.fields) {
60
+ const key = typeof field === "string" ? field : field.key;
61
+ this.reporter.log(`Field: ${this.reporter.format.greenBright(key)}`);
62
+ if (typeof field !== "string" && field.example != null) {
63
+ this.reporter.log(`Example: ${this.reporter.format.magentaBright(field.example)}`);
64
+ }
65
+ collectedValues[key] = await this.getInput({
66
+ prompt: "Enter value (Ctrl+C to abort): ",
67
+ silent: this.silent,
68
+ });
69
+ this.reporter.log("");
70
+ }
71
+ return JSON.stringify(collectedValues, undefined, " ");
72
+ }
73
+ getFullName(secretGroup, secret) {
74
+ return `${secretGroup.namePrefix}${secret.name}`;
75
+ }
76
+ async syncTags(client, secret, tags) {
77
+ const keysToRemove = secret
78
+ .Tags.filter((existingTag) => !tags.some((it) => it.Key === existingTag.Key))
79
+ .map((it) => it.Key);
80
+ if (keysToRemove.length > 0) {
81
+ this.reporter.log(`Removing obsolete tags: ${keysToRemove.join(", ")}`);
82
+ await client.send(new UntagResourceCommand({
83
+ SecretId: secret.ARN,
84
+ TagKeys: keysToRemove,
85
+ }));
86
+ }
87
+ const tagsToUpdate = tags.filter((expectedTag) => {
88
+ const existing = secret.Tags.find((it) => it.Key === expectedTag.Key);
89
+ return existing == null || existing.Value != expectedTag.Value;
90
+ });
91
+ if (tagsToUpdate.length > 0) {
92
+ this.reporter.log(`Storing tags: ${tagsToUpdate.map((it) => it.Key).join(", ")}`);
93
+ await client.send(new TagResourceCommand({
94
+ SecretId: secret.ARN,
95
+ Tags: tagsToUpdate,
96
+ }));
97
+ }
98
+ }
99
+ async getSecretValue(client, secretId) {
100
+ const result = await client.send(new GetSecretValueCommand({
101
+ SecretId: secretId,
102
+ }));
103
+ if (result.SecretString == null) {
104
+ throw new Error("Missing SecretString (is it a binary?)");
105
+ }
106
+ return result.SecretString;
107
+ }
108
+ async handleUpdate(secretGroup, secret) {
109
+ const client = this.getSmClient(secretGroup.region);
110
+ const fullName = this.getFullName(secretGroup, secret);
111
+ const describeSecret = await this.getSecretDetails(client, fullName);
112
+ this.reporter.log(`Secret: ${this.reporter.format.greenBright(fullName)}`);
113
+ if (describeSecret == null) {
114
+ this.reporter.log("The secret does not already exist and will be created");
115
+ }
116
+ else {
117
+ this.reporter.log("Current value:");
118
+ this.reporter.log(this.reporter.format.yellowBright((await this.getSecretValue(client, fullName)).replace(/^/gm, " ")));
119
+ }
120
+ this.reporter.log("");
121
+ let secretValue;
122
+ if (secret.type === "json") {
123
+ try {
124
+ secretValue = await this.handleJsonUpdate(secret);
125
+ }
126
+ catch (e) {
127
+ if (e instanceof Error && e.message === "canceled") {
128
+ this.reporter.log("Aborted");
129
+ return;
130
+ }
131
+ throw e;
132
+ }
133
+ }
134
+ else if (secret.type === "string") {
135
+ secretValue = await this.handleStringUpdate();
136
+ }
137
+ else {
138
+ throw new Error(`Unsupported type`);
139
+ }
140
+ this.reporter.log("Storing secret value:");
141
+ this.reporter.log(this.reporter.format.yellowBright(secretValue.replace(/^/gm, " ")));
142
+ const tags = [
143
+ {
144
+ Key: "Source",
145
+ Value: "load-secrets script",
146
+ },
147
+ ];
148
+ let arn;
149
+ let version;
150
+ let newReplicaRegions;
151
+ let removedReplicaRegions = [];
152
+ if (describeSecret == null) {
153
+ newReplicaRegions = secret.replicaRegions ?? [];
154
+ const createResult = await client.send(new CreateSecretCommand({
155
+ Name: fullName,
156
+ AddReplicaRegions: secret.replicaRegions
157
+ ? secret.replicaRegions.map((replicaRegion) => ({
158
+ Region: replicaRegion,
159
+ }))
160
+ : undefined,
161
+ Description: "Created by load-secrets",
162
+ SecretString: secretValue,
163
+ Tags: tags,
164
+ }));
165
+ if (createResult.VersionId == null) {
166
+ throw new Error("Expected versionId");
167
+ }
168
+ arn = createResult.ARN;
169
+ version = createResult.VersionId;
170
+ }
171
+ else {
172
+ if (describeSecret.DeletedDate != null) {
173
+ await client.send(new RestoreSecretCommand({
174
+ SecretId: fullName,
175
+ }));
176
+ }
177
+ const updateResult = await client.send(new PutSecretValueCommand({
178
+ SecretId: fullName,
179
+ SecretString: secretValue,
180
+ }));
181
+ const currentReplicaRegions = describeSecret.ReplicationStatus?.map((replicationStatus) => replicationStatus.Region) ?? [];
182
+ newReplicaRegions =
183
+ secret.replicaRegions?.filter((region) => !currentReplicaRegions.includes(region)) ?? [];
184
+ removedReplicaRegions = currentReplicaRegions
185
+ .filter((region) => !!region && true)
186
+ .filter((region) => !(secret.replicaRegions || []).includes(region));
187
+ if (newReplicaRegions.length > 0) {
188
+ await client.send(new ReplicateSecretToRegionsCommand({
189
+ SecretId: fullName,
190
+ AddReplicaRegions: newReplicaRegions.map((region) => ({
191
+ Region: region,
192
+ })),
193
+ }));
194
+ }
195
+ if (removedReplicaRegions.length > 0) {
196
+ await client.send(new RemoveRegionsFromReplicationCommand({
197
+ SecretId: fullName,
198
+ RemoveReplicaRegions: removedReplicaRegions,
199
+ }));
200
+ }
201
+ if (updateResult.VersionId == null) {
202
+ throw new Error("Expected versionId");
203
+ }
204
+ await this.syncTags(client, describeSecret, tags);
205
+ arn = updateResult.ARN;
206
+ version = updateResult.VersionId;
207
+ }
208
+ this.reporter.log("");
209
+ this.reporter.log("Secret stored:");
210
+ this.reporter.log(`ARN: ${this.reporter.format.greenBright(arn)}`);
211
+ this.reporter.log(`Version: ${this.reporter.format.greenBright(version)}`);
212
+ if (newReplicaRegions.length > 0) {
213
+ this.reporter.log(`Read replicas added to regions: ${newReplicaRegions
214
+ .map((r) => this.reporter.format.greenBright(r))
215
+ .join(", ")}`);
216
+ }
217
+ if (removedReplicaRegions.length > 0) {
218
+ this.reporter.log(`Read replicas removed from regions: ${removedReplicaRegions
219
+ .map((r) => this.reporter.format.redBright(r))
220
+ .join(", ")}`);
221
+ }
222
+ }
223
+ checkSecretGroup(secretGroup) {
224
+ if (!secretGroup.namePrefix.startsWith("/") ||
225
+ !secretGroup.namePrefix.endsWith("/")) {
226
+ throw new Error(`namePrefix should start and end with /. Current value: ${secretGroup.namePrefix}`);
227
+ }
228
+ }
229
+ getSecretDescription(details) {
230
+ return details == null
231
+ ? "not yet created"
232
+ : details?.DeletedDate != null
233
+ ? `scheduled for deletion ${details.DeletedDate.toISOString()}`
234
+ : `last changed ${details.LastChangedDate?.toISOString() ?? "unknown"}`;
235
+ }
236
+ /**
237
+ * Returns false if aborted.
238
+ */
239
+ async selectAndUpdate(secretGroups) {
240
+ const secrets = [];
241
+ this.reporter.log("Select secret to write:");
242
+ this.reporter.log("");
243
+ for (const secretGroup of secretGroups) {
244
+ this.reporter.log(`${secretGroup.description} (prefix: ${secretGroup.namePrefix})`);
245
+ for (let i = 0; i < secretGroup.secrets.length; i++) {
246
+ const offset = secrets.length;
247
+ const secret = secretGroup.secrets[i];
248
+ secrets.push({
249
+ secret: secret,
250
+ secretGroup,
251
+ });
252
+ const client = this.getSmClient(secretGroup.region);
253
+ const details = await this.getSecretDetails(client, this.getFullName(secretGroup, secret));
254
+ const desc = this.getSecretDescription(details);
255
+ this.reporter.log(` (${offset}) ${secret.name} (${desc})`);
256
+ }
257
+ this.reporter.log("");
258
+ }
259
+ let index;
260
+ try {
261
+ const answer = await this.getInput({
262
+ prompt: "Enter index (or enter to quit): ",
263
+ });
264
+ if (answer.trim() === "") {
265
+ return false;
266
+ }
267
+ index = parseInt(answer);
268
+ if (!secrets[index]) {
269
+ throw new Error();
270
+ }
271
+ }
272
+ catch (_) {
273
+ this.reporter.warn("Secret not found - aborting");
274
+ return false;
275
+ }
276
+ this.reporter.log("");
277
+ await this.handleUpdate(secrets[index].secretGroup, secrets[index].secret);
278
+ this.reporter.log("");
279
+ return true;
280
+ }
281
+ async process(secretGroups) {
282
+ this.reporter.info("Checking account for current credentials");
283
+ this.reporter.info("If any error is given, make sure you have valid credentials active");
284
+ const currentAccount = await this.stsClient.send(new GetCallerIdentityCommand({}));
285
+ this.reporter.info(`Running for account ${currentAccount.Account}`);
286
+ this.reporter.log("");
287
+ const matchedSecretGroups = secretGroups.filter((it) => it.accountId === currentAccount.Account);
288
+ if (matchedSecretGroups.length === 0) {
289
+ this.reporter.error(`No secrets specified for this account - aborting`);
290
+ return;
291
+ }
292
+ for (const secretGroup of matchedSecretGroups) {
293
+ this.checkSecretGroup(secretGroup);
294
+ }
295
+ // eslint-disable-next-line no-empty
296
+ while (await this.selectAndUpdate(matchedSecretGroups)) { }
297
+ }
298
+ }
299
+ /**
300
+ * Load secrets interactively into Secrets Manager.
301
+ */
302
+ export function loadSecretsCli(props) {
303
+ const loadSecrets = new LoadSecrets({
304
+ reporter: createReporter({}),
305
+ // For now, we show the secrets, so that we get positive feedback that the value
306
+ // is correctly entered.
307
+ silent: false,
308
+ });
309
+ loadSecrets.process(props.secretGroups).catch((error) => {
310
+ console.error(error.stack || error.message || error);
311
+ process.exitCode = 1;
312
+ });
313
+ }
314
+ //# sourceMappingURL=load-secrets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-secrets.js","sourceRoot":"","sources":["../../src/load-secrets/load-secrets.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ export interface BaseSecret {
2
+ name: string;
3
+ description?: string;
4
+ /**
5
+ * A list of regions to create read replicas
6
+ * of the secret in.
7
+ */
8
+ replicaRegions?: string[];
9
+ }
10
+ export type JsonSecretSimpleField = string;
11
+ export interface JsonSecretDescribedField {
12
+ key: string;
13
+ description?: string;
14
+ example?: string;
15
+ }
16
+ /**
17
+ * Used for secrets that are a single plaintext string,
18
+ * and do not require JSON formating.
19
+ */
20
+ export interface StringSecret extends BaseSecret {
21
+ type: "string";
22
+ }
23
+ export interface JsonSecret extends BaseSecret {
24
+ type: "json";
25
+ fields: (JsonSecretSimpleField | JsonSecretDescribedField)[];
26
+ }
27
+ export type Secret = JsonSecret | StringSecret;
28
+ export interface SecretGroup {
29
+ accountId: string;
30
+ region: string;
31
+ description: string;
32
+ namePrefix: string;
33
+ secrets: Secret[];
34
+ }
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/load-secrets/types.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liflig/load-secrets",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "Library for loading project secrets into AWS Secrets Manager",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -10,7 +10,7 @@
10
10
  "url": "git+https://github.com/capralifecycle/load-secrets.git"
11
11
  },
12
12
  "scripts": {
13
- "prepare": "husky",
13
+ "prepare": "npm run build && husky",
14
14
  "build": "tsc",
15
15
  "lint": "eslint .",
16
16
  "lint:fix": "eslint --fix .",
@@ -23,6 +23,7 @@
23
23
  "@aws-sdk/client-secrets-manager": "3.699.0",
24
24
  "@aws-sdk/client-sts": "3.699.0",
25
25
  "chalk": "4.0.0",
26
+ "read": "4.0.0",
26
27
  "typescript": "5.7.2"
27
28
  },
28
29
  "devDependencies": {
package/renovate.json5 ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "extends": [
3
+ "github>capraconsulting/renovate-config:library",
4
+ "github>capraconsulting/renovate-config:aggressive"
5
+ ]
6
+ }
@@ -7,16 +7,17 @@ import {
7
7
  DescribeSecretCommand,
8
8
  GetSecretValueCommand,
9
9
  PutSecretValueCommand,
10
+ RemoveRegionsFromReplicationCommand,
11
+ ReplicateSecretToRegionsCommand,
12
+ ResourceNotFoundException,
10
13
  RestoreSecretCommand,
11
14
  SecretsManagerClient,
12
15
  TagResourceCommand,
13
16
  UntagResourceCommand,
14
- ReplicateSecretToRegionsCommand,
15
- RemoveRegionsFromReplicationCommand,
16
17
  } from "@aws-sdk/client-secrets-manager";
17
18
  import { GetCallerIdentityCommand, STSClient } from "@aws-sdk/client-sts";
18
- import { ResourceNotFoundException } from "@aws-sdk/client-secrets-manager";
19
- import read from "read";
19
+ import type { Options } from "read";
20
+ import { read } from "read";
20
21
  import type { CLIReporter } from "../cli/reporter";
21
22
  import { createReporter } from "../cli/reporter";
22
23
 
@@ -48,15 +49,8 @@ class LoadSecrets {
48
49
  return this.smClientForRegions[region];
49
50
  }
50
51
 
51
- async getInput(options: read.Options): Promise<string> {
52
- return new Promise<string>((resolve, reject) => {
53
- read(options, (err, answer) => {
54
- if (err) {
55
- reject(err);
56
- }
57
- resolve(answer);
58
- });
59
- });
52
+ async getInput(options: Options): Promise<string> {
53
+ return read(options);
60
54
  }
61
55
 
62
56
  async getSecretDetails(
@@ -111,11 +105,10 @@ class LoadSecrets {
111
105
  );
112
106
  }
113
107
 
114
- const value = await this.getInput({
108
+ collectedValues[key] = await this.getInput({
115
109
  prompt: "Enter value (Ctrl+C to abort): ",
116
110
  silent: this.silent,
117
111
  });
118
- collectedValues[key] = value;
119
112
 
120
113
  this.reporter.log("");
121
114
  }
@@ -235,7 +228,7 @@ class LoadSecrets {
235
228
 
236
229
  let arn: string;
237
230
  let version: string;
238
- let newReplicaRegions: string[] = [];
231
+ let newReplicaRegions: string[];
239
232
  let removedReplicaRegions: string[] = [];
240
233
 
241
234
  if (describeSecret == null) {
@@ -284,9 +277,7 @@ class LoadSecrets {
284
277
  (region) => !currentReplicaRegions.includes(region),
285
278
  ) ?? [];
286
279
  removedReplicaRegions = currentReplicaRegions
287
- .filter(
288
- (region): region is string => !!region && typeof region === "string",
289
- )
280
+ .filter((region): region is string => !!region && true)
290
281
  .filter((region) => !(secret.replicaRegions || []).includes(region));
291
282
  if (newReplicaRegions.length > 0) {
292
283
  await client.send(