updating-secrets 0.2.0 → 0.3.1
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/dist/adapters/aws-secrets-manager.adapter.d.ts +2 -2
- package/dist/adapters/base.adapter.d.ts +2 -2
- package/dist/adapters/infisical.adapter.d.ts +70 -0
- package/dist/adapters/infisical.adapter.js +168 -0
- package/dist/adapters/secrets-json-file.adapter.d.ts +1 -1
- package/dist/adapters/static-secrets.adapter.d.ts +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/public-mocks/mock-fs.d.ts +3 -3
- package/dist/public-mocks/mock-infisical-sdk.d.ts +70 -0
- package/dist/public-mocks/mock-infisical-sdk.js +84 -0
- package/dist/secrets-definition/define-secrets.d.ts +20 -2
- package/dist/updating-secrets.d.ts +3 -4
- package/package.json +29 -27
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ProcessedSecretDefinitions } from '../secrets-definition/define-secrets.js';
|
|
1
|
+
import { type GetSecretValueCommand, type GetSecretValueCommandOutput } from '@aws-sdk/client-secrets-manager';
|
|
2
|
+
import { type ProcessedSecretDefinitions } from '../secrets-definition/define-secrets.js';
|
|
3
3
|
import { BaseSecretsAdapter } from './base.adapter.js';
|
|
4
4
|
/**
|
|
5
5
|
* Minimal subset of AWS's `SecretsManagerClient` from the
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import { ProcessedSecretDefinitions } from '../secrets-definition/define-secrets.js';
|
|
1
|
+
import { type JsonCompatibleValue, type MaybePromise } from '@augment-vir/common';
|
|
2
|
+
import { type ProcessedSecretDefinitions } from '../secrets-definition/define-secrets.js';
|
|
3
3
|
/**
|
|
4
4
|
* Raw secret values as returned by an adapter's `loadSecrets` method.
|
|
5
5
|
*
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { type Values } from '@augment-vir/common';
|
|
2
|
+
import { type ListSecretsOptions, type Secret } from '@infisical/sdk';
|
|
3
|
+
import { type ProcessedSecretDefinitions } from '../secrets-definition/define-secrets.js';
|
|
4
|
+
import { BaseSecretsAdapter, type RawSecrets } from './base.adapter.js';
|
|
5
|
+
/**
|
|
6
|
+
* Intermediate type for processing secrets from Infisical. Used in {@link InfisicalAdapter} and
|
|
7
|
+
* helper functions.
|
|
8
|
+
*
|
|
9
|
+
* @category Internal
|
|
10
|
+
*/
|
|
11
|
+
export type MappedInfisicalSecrets = {
|
|
12
|
+
[SecretKey in string]: string | MappedInfisicalSecrets | Error;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* The necessary subset of the `InfisicalSDK` API that {@link InfisicalAdapter} requires.
|
|
16
|
+
*
|
|
17
|
+
* @category Internal
|
|
18
|
+
*/
|
|
19
|
+
export type NeededInfisicalSdk = {
|
|
20
|
+
/** Get the Infisical secrets client. */
|
|
21
|
+
secrets(): {
|
|
22
|
+
/** List the Infisical secrets. */
|
|
23
|
+
listSecrets(options: ListSecretsOptions): Promise<{
|
|
24
|
+
secrets: NeededInfisicalSecret[];
|
|
25
|
+
}>;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* The necessary subset of the Infisical `Secret` type that {@link InfisicalAdapter} requires.
|
|
30
|
+
*
|
|
31
|
+
* @category Internal
|
|
32
|
+
*/
|
|
33
|
+
export type NeededInfisicalSecret = Pick<Secret, 'secretKey' | 'secretPath' | 'secretValue'>;
|
|
34
|
+
/**
|
|
35
|
+
* Loads secrets from Infisical. A `InfisicalSDK` instance must be provided. The `InfisicalSDK`
|
|
36
|
+
* instance must also be authorized _before_ passing it into this.
|
|
37
|
+
*
|
|
38
|
+
* @category Adapters
|
|
39
|
+
*/
|
|
40
|
+
export declare class InfisicalAdapter extends BaseSecretsAdapter {
|
|
41
|
+
/**
|
|
42
|
+
* Make sure that you've already authenticated this client.
|
|
43
|
+
* (`client.auth().universalAuth.login()`)
|
|
44
|
+
*/
|
|
45
|
+
protected readonly infisicalClient: Readonly<NeededInfisicalSdk>;
|
|
46
|
+
/** `'dev'`, `'staging'`, `'prod'`, etc. */
|
|
47
|
+
protected readonly infisicalEnvironment: string;
|
|
48
|
+
constructor(
|
|
49
|
+
/**
|
|
50
|
+
* Make sure that you've already authenticated this client.
|
|
51
|
+
* (`client.auth().universalAuth.login()`)
|
|
52
|
+
*/
|
|
53
|
+
infisicalClient: Readonly<NeededInfisicalSdk>,
|
|
54
|
+
/** `'dev'`, `'staging'`, `'prod'`, etc. */
|
|
55
|
+
infisicalEnvironment: string);
|
|
56
|
+
/** Load secrets from the provided `InfisicalSDK`. */
|
|
57
|
+
loadSecrets(secrets: ProcessedSecretDefinitions): RawSecrets;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get an Infisical secret value nested within an object.
|
|
61
|
+
*
|
|
62
|
+
* @category Internal
|
|
63
|
+
*/
|
|
64
|
+
export declare function getNested(parent: MappedInfisicalSecrets, keys: string[]): Values<MappedInfisicalSecrets>;
|
|
65
|
+
/**
|
|
66
|
+
* Set an Infisical secret value nested within an object.
|
|
67
|
+
*
|
|
68
|
+
* @category Internal
|
|
69
|
+
*/
|
|
70
|
+
export declare function setNested(parent: MappedInfisicalSecrets, keys: string[], value: string): void;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { check } from '@augment-vir/assert';
|
|
2
|
+
import { ensureError, getOrSet, mapObjectValuesSync, parseWithJson5, removePrefix, removeSuffix, stringify, wrapInTry, } from '@augment-vir/common';
|
|
3
|
+
import { BaseSecretsAdapter } from './base.adapter.js';
|
|
4
|
+
/**
|
|
5
|
+
* Loads secrets from Infisical. A `InfisicalSDK` instance must be provided. The `InfisicalSDK`
|
|
6
|
+
* instance must also be authorized _before_ passing it into this.
|
|
7
|
+
*
|
|
8
|
+
* @category Adapters
|
|
9
|
+
*/
|
|
10
|
+
export class InfisicalAdapter extends BaseSecretsAdapter {
|
|
11
|
+
infisicalClient;
|
|
12
|
+
infisicalEnvironment;
|
|
13
|
+
constructor(
|
|
14
|
+
/**
|
|
15
|
+
* Make sure that you've already authenticated this client.
|
|
16
|
+
* (`client.auth().universalAuth.login()`)
|
|
17
|
+
*/
|
|
18
|
+
infisicalClient,
|
|
19
|
+
/** `'dev'`, `'staging'`, `'prod'`, etc. */
|
|
20
|
+
infisicalEnvironment) {
|
|
21
|
+
super('InfisicalAdapter');
|
|
22
|
+
this.infisicalClient = infisicalClient;
|
|
23
|
+
this.infisicalEnvironment = infisicalEnvironment;
|
|
24
|
+
}
|
|
25
|
+
/** Load secrets from the provided `InfisicalSDK`. */
|
|
26
|
+
loadSecrets(secrets) {
|
|
27
|
+
const secretsCache = {};
|
|
28
|
+
return mapObjectValuesSync(secrets, (secretName, secretDefinition) => {
|
|
29
|
+
const infisicalConfig = secretDefinition.adapterConfig.infisical;
|
|
30
|
+
if (!infisicalConfig) {
|
|
31
|
+
return new Error(`No Infisical adapter config (required for using InfisicalAdapter) defined for secret '${secretDefinition.secretName}'.`);
|
|
32
|
+
}
|
|
33
|
+
const projectSecretsPromise = getOrSet(secretsCache, infisicalConfig.projectId, () => {
|
|
34
|
+
try {
|
|
35
|
+
return (this.infisicalClient
|
|
36
|
+
.secrets()
|
|
37
|
+
.listSecrets({
|
|
38
|
+
recursive: true,
|
|
39
|
+
environment: this.infisicalEnvironment,
|
|
40
|
+
projectId: infisicalConfig.projectId,
|
|
41
|
+
viewSecretValue: true,
|
|
42
|
+
})
|
|
43
|
+
.then(({ secrets }) => {
|
|
44
|
+
return mapInfisicalSecrets(secrets);
|
|
45
|
+
})
|
|
46
|
+
/* node:coverage ignore next 3 */
|
|
47
|
+
.catch((error) => {
|
|
48
|
+
return ensureError(error);
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
return Promise.reject(ensureError(error));
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
return projectSecretsPromise
|
|
56
|
+
.then((projectSecrets) => {
|
|
57
|
+
/* node:coverage ignore next 3 */
|
|
58
|
+
if (projectSecrets instanceof Error) {
|
|
59
|
+
return projectSecrets;
|
|
60
|
+
}
|
|
61
|
+
const folderValue = infisicalConfig.folderPath === '/' || !infisicalConfig.folderPath
|
|
62
|
+
? projectSecrets
|
|
63
|
+
: getNested(projectSecrets, removeSuffix({
|
|
64
|
+
value: removePrefix({
|
|
65
|
+
value: infisicalConfig.folderPath,
|
|
66
|
+
prefix: '/',
|
|
67
|
+
}),
|
|
68
|
+
suffix: '/',
|
|
69
|
+
}).split('/'));
|
|
70
|
+
/* node:coverage ignore next 3 */
|
|
71
|
+
if (check.isError(folderValue)) {
|
|
72
|
+
return folderValue;
|
|
73
|
+
}
|
|
74
|
+
if (infisicalConfig.keyInFolder) {
|
|
75
|
+
if (check.isString(folderValue)) {
|
|
76
|
+
throw new TypeError(`Cannot get keyInFolder of a non-folder.`);
|
|
77
|
+
}
|
|
78
|
+
else if (check.hasKey(folderValue, infisicalConfig.keyInFolder)) {
|
|
79
|
+
const value = folderValue[infisicalConfig.keyInFolder];
|
|
80
|
+
if (secretDefinition.shapeDefinition && check.isString(value)) {
|
|
81
|
+
return wrapInTry(() => parseWithJson5(value), {
|
|
82
|
+
fallbackValue: folderValue,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
return value;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
throw new Error(`Secret key not in folder '${infisicalConfig.folderPath}'`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
return folderValue;
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
.catch((error) => {
|
|
98
|
+
return ensureError(error);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function mapInfisicalSecrets(secrets) {
|
|
104
|
+
const secretsMap = {};
|
|
105
|
+
secrets.forEach((secret) => {
|
|
106
|
+
if (!secret.secretPath || secret.secretPath === '/') {
|
|
107
|
+
secretsMap[secret.secretKey] = secret.secretValue;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
setNested(secretsMap, removeSuffix({
|
|
111
|
+
value: removePrefix({ value: secret.secretPath, prefix: '/' }),
|
|
112
|
+
suffix: '/',
|
|
113
|
+
})
|
|
114
|
+
.split('/')
|
|
115
|
+
.concat(secret.secretKey), secret.secretValue);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
return secretsMap;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Get an Infisical secret value nested within an object.
|
|
122
|
+
*
|
|
123
|
+
* @category Internal
|
|
124
|
+
*/
|
|
125
|
+
export function getNested(parent, keys) {
|
|
126
|
+
const nextKey = keys[0];
|
|
127
|
+
if (nextKey == undefined) {
|
|
128
|
+
throw new Error('Invalid key or ran out of keys.');
|
|
129
|
+
}
|
|
130
|
+
const nextParent = parent[nextKey];
|
|
131
|
+
if (!nextParent) {
|
|
132
|
+
throw new Error(`Nothing at key '${nextKey}'`);
|
|
133
|
+
}
|
|
134
|
+
else if (nextParent instanceof Error) {
|
|
135
|
+
throw nextParent;
|
|
136
|
+
}
|
|
137
|
+
if (keys.length > 1) {
|
|
138
|
+
if (check.isString(nextParent)) {
|
|
139
|
+
throw new TypeError(`Keys still remain but received string value: ${stringify({ keys })}`);
|
|
140
|
+
}
|
|
141
|
+
return getNested(nextParent, keys.slice(1));
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
return nextParent;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Set an Infisical secret value nested within an object.
|
|
149
|
+
*
|
|
150
|
+
* @category Internal
|
|
151
|
+
*/
|
|
152
|
+
export function setNested(parent, keys, value) {
|
|
153
|
+
const nextKey = keys[0];
|
|
154
|
+
if (nextKey == undefined) {
|
|
155
|
+
throw new Error('Invalid key or ran out of keys.');
|
|
156
|
+
}
|
|
157
|
+
if (keys.length === 1) {
|
|
158
|
+
parent[nextKey] = value;
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const nextParent = getOrSet(parent, nextKey, () => {
|
|
162
|
+
return {};
|
|
163
|
+
});
|
|
164
|
+
if (check.isString(nextParent) || check.isError(nextParent)) {
|
|
165
|
+
throw new TypeError(`Cannot set key '${nextKey}'; it's already set to a non-object.`);
|
|
166
|
+
}
|
|
167
|
+
return setNested(nextParent, keys.slice(1), value);
|
|
168
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type MaybePromise, type PartialWithUndefined } from '@augment-vir/common';
|
|
2
|
-
import type
|
|
2
|
+
import { type SecretDefinitions, type SecretValues } from '../secrets-definition/define-secrets.js';
|
|
3
3
|
import { BaseSecretsAdapter } from './base.adapter.js';
|
|
4
4
|
/**
|
|
5
5
|
* Options for {@link SecretsJsonFileAdapter}.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type JsonCompatibleValue } from '@augment-vir/common';
|
|
2
2
|
import { BaseSecretsAdapter } from './base.adapter.js';
|
|
3
3
|
/**
|
|
4
4
|
* This adapter is constructed with a static set of secrets and that static set of secrets is always
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
export * from './adapters/all-adapters.js';
|
|
2
2
|
export * from './adapters/aws-secrets-manager.adapter.js';
|
|
3
3
|
export * from './adapters/base.adapter.js';
|
|
4
|
+
export * from './adapters/infisical.adapter.js';
|
|
4
5
|
export * from './adapters/secrets-json-file.adapter.js';
|
|
5
6
|
export * from './adapters/static-secrets.adapter.js';
|
|
6
7
|
export * from './public-mocks/mock-aws-secrets-manager.js';
|
|
7
8
|
export * from './public-mocks/mock-fs.js';
|
|
9
|
+
export * from './public-mocks/mock-infisical-sdk.js';
|
|
8
10
|
export * from './secret-load.error.js';
|
|
9
11
|
export * from './secrets-definition/define-secrets.js';
|
|
10
12
|
export * from './updating-secrets.js';
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
export * from './adapters/all-adapters.js';
|
|
2
2
|
export * from './adapters/aws-secrets-manager.adapter.js';
|
|
3
3
|
export * from './adapters/base.adapter.js';
|
|
4
|
+
export * from './adapters/infisical.adapter.js';
|
|
4
5
|
export * from './adapters/secrets-json-file.adapter.js';
|
|
5
6
|
export * from './adapters/static-secrets.adapter.js';
|
|
6
7
|
export * from './public-mocks/mock-aws-secrets-manager.js';
|
|
7
8
|
export * from './public-mocks/mock-fs.js';
|
|
9
|
+
export * from './public-mocks/mock-infisical-sdk.js';
|
|
8
10
|
export * from './secret-load.error.js';
|
|
9
11
|
export * from './secrets-definition/define-secrets.js';
|
|
10
12
|
export * from './updating-secrets.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import type
|
|
3
|
-
import { SecretsJsonFileAdapterOptions } from '../adapters/secrets-json-file.adapter.js';
|
|
1
|
+
import { type MaybePromise } from '@augment-vir/common';
|
|
2
|
+
import { type RequireExactlyOne } from 'type-fest';
|
|
3
|
+
import { type SecretsJsonFileAdapterOptions } from '../adapters/secrets-json-file.adapter.js';
|
|
4
4
|
/**
|
|
5
5
|
* Mock data for {@link createMockFs}. There are two possible options contained herein, but only one
|
|
6
6
|
* may be used at a time.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { type JsonCompatibleValue } from '@augment-vir/common';
|
|
2
|
+
import { type InfisicalSDK, type ListSecretsOptions, type Secret } from '@infisical/sdk';
|
|
3
|
+
import { type RequireExactlyOne } from 'type-fest';
|
|
4
|
+
/**
|
|
5
|
+
* Mock secrets setup for {@link MockAwsSecretsManagerClient}.
|
|
6
|
+
*
|
|
7
|
+
* @category Internal
|
|
8
|
+
*/
|
|
9
|
+
export type MockInfisicalSecrets = {
|
|
10
|
+
projectId: string;
|
|
11
|
+
/** `'dev'`, `'staging'`, `'prod'`, etc. */
|
|
12
|
+
env: string;
|
|
13
|
+
secrets: {
|
|
14
|
+
[SecretKey in string]: {
|
|
15
|
+
folderPath?: string | undefined;
|
|
16
|
+
} & RequireExactlyOne<{
|
|
17
|
+
/**
|
|
18
|
+
* A value that will be JSON stringified for the `.SecretString` output of AWS Secrets
|
|
19
|
+
* Manager.
|
|
20
|
+
*/
|
|
21
|
+
preJson: JsonCompatibleValue;
|
|
22
|
+
/** Set the raw `.SecretString` output of AWS Secrets Manager directly. */
|
|
23
|
+
rawString: string;
|
|
24
|
+
}>;
|
|
25
|
+
};
|
|
26
|
+
}[];
|
|
27
|
+
/**
|
|
28
|
+
* A mock implementation of `InfisicalSDK` from the
|
|
29
|
+
* [@infisical/sdk](https://www.npmjs.com/package/@infisical/sdk) package. This only mocks what is
|
|
30
|
+
* necessary for the infisical adapter to work.
|
|
31
|
+
*
|
|
32
|
+
* @category Mocks
|
|
33
|
+
*/
|
|
34
|
+
export declare class MockInfisicalSdk {
|
|
35
|
+
/** Mock secrets that will be used in `secrets().listSecrets()` */
|
|
36
|
+
readonly mockSecrets: Readonly<MockInfisicalSecrets>;
|
|
37
|
+
/** Keeps track of whether this SDK has been authorized or not. */
|
|
38
|
+
protected isAuthorized: boolean;
|
|
39
|
+
constructor(
|
|
40
|
+
/** Mock secrets that will be used in `secrets().listSecrets()` */
|
|
41
|
+
mockSecrets: Readonly<MockInfisicalSecrets>);
|
|
42
|
+
/** Mock of `InfisicalSDK.auth()` */
|
|
43
|
+
auth(): {
|
|
44
|
+
/** Mock of `InfisicalSDK.auth().universalAuth` */
|
|
45
|
+
universalAuth: {
|
|
46
|
+
/** Mock of `InfisicalSDK.auth().universalAuth.login()` */
|
|
47
|
+
login: (options: import("@infisical/sdk").UniversalAuthLoginRequest) => Promise<InfisicalSDK>;
|
|
48
|
+
/** Mock of `InfisicalSDK.auth().universalAuth.renew()` */
|
|
49
|
+
renew(): never;
|
|
50
|
+
};
|
|
51
|
+
/** Mock of `InfisicalSDK.auth().accessToken` */
|
|
52
|
+
accessToken: (token: string) => InfisicalSDK;
|
|
53
|
+
/** Mock of `InfisicalSDK.auth().awsIamAuth` */
|
|
54
|
+
awsIamAuth: {
|
|
55
|
+
/** Mock of `InfisicalSDK.auth().awsIamAuth.login()` */
|
|
56
|
+
login: (options?: {
|
|
57
|
+
identityId?: string;
|
|
58
|
+
} | undefined) => Promise<InfisicalSDK>;
|
|
59
|
+
/** Mock of `InfisicalSDK.auth().awsIamAuth.renew()` */
|
|
60
|
+
renew(): never;
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
/** Mock of `InfisicalSDK.secrets()` */
|
|
64
|
+
secrets(): {
|
|
65
|
+
/** Mock of `InfisicalSDK.secrets().listSecrets()` */
|
|
66
|
+
listSecrets: ({ projectId, environment }: ListSecretsOptions) => Promise<{
|
|
67
|
+
secrets: Partial<Secret>[];
|
|
68
|
+
}>;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { getObjectTypedEntries, stringifyWithJson5, } from '@augment-vir/common';
|
|
2
|
+
/**
|
|
3
|
+
* A mock implementation of `InfisicalSDK` from the
|
|
4
|
+
* [@infisical/sdk](https://www.npmjs.com/package/@infisical/sdk) package. This only mocks what is
|
|
5
|
+
* necessary for the infisical adapter to work.
|
|
6
|
+
*
|
|
7
|
+
* @category Mocks
|
|
8
|
+
*/
|
|
9
|
+
export class MockInfisicalSdk {
|
|
10
|
+
mockSecrets;
|
|
11
|
+
/** Keeps track of whether this SDK has been authorized or not. */
|
|
12
|
+
isAuthorized = false;
|
|
13
|
+
constructor(
|
|
14
|
+
/** Mock secrets that will be used in `secrets().listSecrets()` */
|
|
15
|
+
mockSecrets) {
|
|
16
|
+
this.mockSecrets = mockSecrets;
|
|
17
|
+
}
|
|
18
|
+
/** Mock of `InfisicalSDK.auth()` */
|
|
19
|
+
auth() {
|
|
20
|
+
return {
|
|
21
|
+
/** Mock of `InfisicalSDK.auth().universalAuth` */
|
|
22
|
+
universalAuth: {
|
|
23
|
+
/** Mock of `InfisicalSDK.auth().universalAuth.login()` */
|
|
24
|
+
login: (
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
26
|
+
...params) => {
|
|
27
|
+
this.isAuthorized = true;
|
|
28
|
+
return Promise.resolve(this);
|
|
29
|
+
},
|
|
30
|
+
/** Mock of `InfisicalSDK.auth().universalAuth.renew()` */
|
|
31
|
+
renew() {
|
|
32
|
+
throw new Error('Not mocked.');
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
/** Mock of `InfisicalSDK.auth().accessToken` */
|
|
36
|
+
accessToken: (
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
38
|
+
...params) => {
|
|
39
|
+
this.isAuthorized = true;
|
|
40
|
+
return this;
|
|
41
|
+
},
|
|
42
|
+
/** Mock of `InfisicalSDK.auth().awsIamAuth` */
|
|
43
|
+
awsIamAuth: {
|
|
44
|
+
/** Mock of `InfisicalSDK.auth().awsIamAuth.login()` */
|
|
45
|
+
login: (
|
|
46
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
47
|
+
...params) => {
|
|
48
|
+
this.isAuthorized = true;
|
|
49
|
+
return Promise.resolve(this);
|
|
50
|
+
},
|
|
51
|
+
/** Mock of `InfisicalSDK.auth().awsIamAuth.renew()` */
|
|
52
|
+
renew() {
|
|
53
|
+
throw new Error('Not mocked.');
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/** Mock of `InfisicalSDK.secrets()` */
|
|
59
|
+
secrets() {
|
|
60
|
+
return {
|
|
61
|
+
/** Mock of `InfisicalSDK.secrets().listSecrets()` */
|
|
62
|
+
listSecrets: ({ projectId, environment }) => {
|
|
63
|
+
if (!this.isAuthorized) {
|
|
64
|
+
throw new Error('Mock Infisical SDK client not authorized.');
|
|
65
|
+
}
|
|
66
|
+
const secrets = this.mockSecrets.find((mock) => mock.projectId === projectId && mock.env === environment)?.secrets;
|
|
67
|
+
if (!secrets) {
|
|
68
|
+
throw new Error('Invalid project.');
|
|
69
|
+
}
|
|
70
|
+
return Promise.resolve({
|
|
71
|
+
secrets: getObjectTypedEntries(secrets).map(([secretKey, mockDefinition,]) => {
|
|
72
|
+
return {
|
|
73
|
+
secretPath: mockDefinition.folderPath || '/',
|
|
74
|
+
secretKey,
|
|
75
|
+
secretValue: mockDefinition.preJson
|
|
76
|
+
? stringifyWithJson5(mockDefinition.preJson)
|
|
77
|
+
: mockDefinition.rawString || '',
|
|
78
|
+
};
|
|
79
|
+
}),
|
|
80
|
+
});
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type PartialWithUndefined, type Values } from '@augment-vir/common';
|
|
2
2
|
import { type ShapeDefinition } from 'object-shape-tester';
|
|
3
|
-
import type
|
|
3
|
+
import { type Exact, type RequireExactlyOne } from 'type-fest';
|
|
4
4
|
/**
|
|
5
5
|
* The shape definition for built-in handling of secret rotation. Use this shape in a secret
|
|
6
6
|
* definition's `shape` property (when using {@link defineSecrets}).
|
|
@@ -67,6 +67,22 @@ export type SecretDefinitions = {
|
|
|
67
67
|
*/
|
|
68
68
|
whereToFind: string;
|
|
69
69
|
adapterConfig?: PartialWithUndefined<{
|
|
70
|
+
infisical: {
|
|
71
|
+
projectId: string;
|
|
72
|
+
folderPath?: string;
|
|
73
|
+
} & RequireExactlyOne<{
|
|
74
|
+
/**
|
|
75
|
+
* The name of the secret key within the given folder path. Use this when this
|
|
76
|
+
* secret definition corresponds exactly to a single secret entry in Infisical.
|
|
77
|
+
*/
|
|
78
|
+
keyInFolder: string;
|
|
79
|
+
/**
|
|
80
|
+
* Set this to `true` to use the entire folder's contents as this secret's value.
|
|
81
|
+
* The folder will be loaded recursively, meaning all folders within this folder
|
|
82
|
+
* will also be loaded.
|
|
83
|
+
*/
|
|
84
|
+
useWholeFolder: true;
|
|
85
|
+
}>;
|
|
70
86
|
/**
|
|
71
87
|
* Configuration for loading this secret from AWS. This is required if you're using the
|
|
72
88
|
* AWS SecretsManager adapter, otherwise the secret will fail to load.
|
|
@@ -114,7 +130,9 @@ export type SecretDefinitions = {
|
|
|
114
130
|
*
|
|
115
131
|
* @category Define Secrets
|
|
116
132
|
*/
|
|
117
|
-
export declare function defineSecrets<const Secrets extends
|
|
133
|
+
export declare function defineSecrets<const Secrets extends {
|
|
134
|
+
[Key in keyof Secrets]: Exact<Values<SecretDefinitions>, Secrets[Key]>;
|
|
135
|
+
} & SecretDefinitions>(secrets: Secrets): Secrets;
|
|
118
136
|
/**
|
|
119
137
|
* Processed secret definitions. This is what will be passed to all adapter `loadSecrets` methods.
|
|
120
138
|
* This type is simply a more uniform and generic version of {@link SecretDefinitions}.
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type PartialWithUndefined, type RequiredAndNotNull, type Values } from '@augment-vir/common';
|
|
2
2
|
import { type AnyDuration } from 'date-vir';
|
|
3
|
-
import type
|
|
4
|
-
import type
|
|
5
|
-
import { ProcessedSecretDefinitions, RotatableSecretValue, SecretValues } from './secrets-definition/define-secrets.js';
|
|
3
|
+
import { type BaseSecretsAdapter } from './adapters/base.adapter.js';
|
|
4
|
+
import { type ProcessedSecretDefinitions, type RotatableSecretValue, type SecretDefinitions, type SecretValues } from './secrets-definition/define-secrets.js';
|
|
6
5
|
/**
|
|
7
6
|
* Options for {@link UpdatingSecrets} and {@link createUpdatingSecrets}.
|
|
8
7
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "updating-secrets",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Automatically update secrets on an interval with support for seamless secret rotation.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"secrets",
|
|
@@ -44,52 +44,54 @@
|
|
|
44
44
|
"test:update": "npm run test update"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@augment-vir/assert": "^31.
|
|
48
|
-
"@augment-vir/common": "^31.
|
|
47
|
+
"@augment-vir/assert": "^31.23.3",
|
|
48
|
+
"@augment-vir/common": "^31.23.3",
|
|
49
49
|
"date-vir": "^7.3.1",
|
|
50
|
-
"object-shape-tester": "^5.1.
|
|
51
|
-
"type-fest": "^4.
|
|
50
|
+
"object-shape-tester": "^5.1.6",
|
|
51
|
+
"type-fest": "^4.41.0"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@augment-vir/test": "^31.
|
|
55
|
-
"@aws-sdk/client-secrets-manager": "^3.
|
|
54
|
+
"@augment-vir/test": "^31.23.3",
|
|
55
|
+
"@aws-sdk/client-secrets-manager": "^3.826.0",
|
|
56
56
|
"@eslint/eslintrc": "^3.3.1",
|
|
57
|
-
"@eslint/js": "^9.
|
|
58
|
-
"@
|
|
59
|
-
"@stylistic/eslint-plugin
|
|
60
|
-
"@
|
|
61
|
-
"@
|
|
57
|
+
"@eslint/js": "^9.28.0",
|
|
58
|
+
"@infisical/sdk": "^4.0.2",
|
|
59
|
+
"@stylistic/eslint-plugin": "^4.4.1",
|
|
60
|
+
"@stylistic/eslint-plugin-ts": "^4.4.1",
|
|
61
|
+
"@types/node": "^22.15.30",
|
|
62
|
+
"@typescript-eslint/eslint-plugin": "^8.33.1",
|
|
62
63
|
"c8": "^10.1.3",
|
|
63
|
-
"cspell": "^
|
|
64
|
-
"dependency-cruiser": "^16.10.
|
|
65
|
-
"esbuild": "^0.25.
|
|
66
|
-
"eslint": "^9.
|
|
67
|
-
"eslint-config-prettier": "^10.1.
|
|
68
|
-
"eslint-plugin-jsdoc": "^50.
|
|
64
|
+
"cspell": "^9.0.2",
|
|
65
|
+
"dependency-cruiser": "^16.10.2",
|
|
66
|
+
"esbuild": "^0.25.5",
|
|
67
|
+
"eslint": "^9.28.0",
|
|
68
|
+
"eslint-config-prettier": "^10.1.5",
|
|
69
|
+
"eslint-plugin-jsdoc": "^50.7.1",
|
|
69
70
|
"eslint-plugin-monorepo-cop": "^1.0.2",
|
|
70
71
|
"eslint-plugin-playwright": "^2.2.0",
|
|
71
|
-
"eslint-plugin-prettier": "^5.
|
|
72
|
+
"eslint-plugin-prettier": "^5.4.1",
|
|
72
73
|
"eslint-plugin-require-extensions": "^0.1.3",
|
|
73
74
|
"eslint-plugin-sonarjs": "^3.0.2",
|
|
74
|
-
"eslint-plugin-unicorn": "^
|
|
75
|
+
"eslint-plugin-unicorn": "^59.0.1",
|
|
75
76
|
"istanbul-smart-text-reporter": "^1.1.5",
|
|
76
77
|
"markdown-code-example-inserter": "^3.0.3",
|
|
77
|
-
"npm-check-updates": "^
|
|
78
|
+
"npm-check-updates": "^18.0.1",
|
|
78
79
|
"prettier": "~3.3.3",
|
|
79
80
|
"prettier-plugin-interpolated-html-tags": "^2.0.1",
|
|
80
81
|
"prettier-plugin-jsdoc": "^1.3.2",
|
|
81
82
|
"prettier-plugin-multiline-arrays": "^4.0.3",
|
|
82
83
|
"prettier-plugin-organize-imports": "^4.1.0",
|
|
83
|
-
"prettier-plugin-packagejson": "^2.5.
|
|
84
|
+
"prettier-plugin-packagejson": "^2.5.15",
|
|
84
85
|
"prettier-plugin-sort-json": "^4.1.1",
|
|
85
|
-
"prettier-plugin-toml": "^2.0.
|
|
86
|
-
"typedoc": "^0.28.
|
|
86
|
+
"prettier-plugin-toml": "^2.0.5",
|
|
87
|
+
"typedoc": "^0.28.5",
|
|
87
88
|
"typescript": "^5.8.3",
|
|
88
|
-
"typescript-eslint": "^8.
|
|
89
|
-
"virmator": "^13.
|
|
89
|
+
"typescript-eslint": "^8.33.1",
|
|
90
|
+
"virmator": "^13.15.4"
|
|
90
91
|
},
|
|
91
92
|
"peerDependencies": {
|
|
92
|
-
"@aws-sdk/client-secrets-manager": ">=3"
|
|
93
|
+
"@aws-sdk/client-secrets-manager": ">=3",
|
|
94
|
+
"@infisical/sdk": ">=4"
|
|
93
95
|
},
|
|
94
96
|
"engines": {
|
|
95
97
|
"node": ">=22"
|