@jaypie/constructs 1.2.57 → 1.2.59
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/README.md +9 -0
- package/dist/cjs/JaypieEnvSecret.d.ts +10 -35
- package/dist/cjs/JaypieLambda.d.ts +3 -2
- package/dist/cjs/JaypieNextJs.d.ts +2 -2
- package/dist/cjs/JaypieSecret.d.ts +59 -0
- package/dist/cjs/__tests__/JaypieSecret.spec.d.ts +1 -0
- package/dist/cjs/helpers/resolveSecrets.d.ts +10 -10
- package/dist/cjs/index.cjs +181 -104
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.ts +1 -0
- package/dist/esm/JaypieEnvSecret.d.ts +10 -35
- package/dist/esm/JaypieLambda.d.ts +3 -2
- package/dist/esm/JaypieNextJs.d.ts +2 -2
- package/dist/esm/JaypieSecret.d.ts +59 -0
- package/dist/esm/__tests__/JaypieSecret.spec.d.ts +1 -0
- package/dist/esm/helpers/resolveSecrets.d.ts +10 -10
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +182 -106
- package/dist/esm/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -1,43 +1,18 @@
|
|
|
1
1
|
import { Construct } from "constructs";
|
|
2
|
-
import { SecretValue, RemovalPolicy, Stack } from "aws-cdk-lib";
|
|
3
2
|
import * as secretsmanager from "aws-cdk-lib/aws-secretsmanager";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
import { Grant, IGrantable, PolicyStatement, AddToResourcePolicyResult } from "aws-cdk-lib/aws-iam";
|
|
7
|
-
export interface JaypieEnvSecretProps {
|
|
3
|
+
import { BuildSecretContext, JaypieSecret, JaypieSecretProps } from "./JaypieSecret";
|
|
4
|
+
export interface JaypieEnvSecretProps extends JaypieSecretProps {
|
|
8
5
|
consumer?: boolean;
|
|
9
|
-
envKey?: string;
|
|
10
6
|
export?: string;
|
|
11
|
-
generateSecretString?: secretsmanager.SecretStringGenerator;
|
|
12
7
|
provider?: boolean;
|
|
13
|
-
removalPolicy?: boolean | RemovalPolicy;
|
|
14
|
-
roleTag?: string;
|
|
15
|
-
vendorTag?: string;
|
|
16
|
-
value?: string;
|
|
17
8
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
9
|
+
/**
|
|
10
|
+
* @deprecated Use {@link JaypieSecret}. JaypieEnvSecret layers an
|
|
11
|
+
* environment-driven provider/consumer cross-stack pattern on top of
|
|
12
|
+
* JaypieSecret and will be removed in 2.0.
|
|
13
|
+
*/
|
|
14
|
+
export declare class JaypieEnvSecret extends JaypieSecret {
|
|
15
|
+
protected static readonly shorthandPrefix: string;
|
|
21
16
|
constructor(scope: Construct, idOrEnvKey: string, props?: JaypieEnvSecretProps);
|
|
22
|
-
|
|
23
|
-
get env(): {
|
|
24
|
-
account: string;
|
|
25
|
-
region: string;
|
|
26
|
-
};
|
|
27
|
-
applyRemovalPolicy(policy: RemovalPolicy): void;
|
|
28
|
-
get secretArn(): string;
|
|
29
|
-
get secretFullArn(): string | undefined;
|
|
30
|
-
get secretName(): string;
|
|
31
|
-
get secretRef(): secretsmanager.SecretReference;
|
|
32
|
-
get encryptionKey(): IKey | undefined;
|
|
33
|
-
get secretValue(): SecretValue;
|
|
34
|
-
secretValueFromJson(key: string): SecretValue;
|
|
35
|
-
grantRead(grantee: IGrantable, versionStages?: string[]): Grant;
|
|
36
|
-
grantWrite(grantee: IGrantable): Grant;
|
|
37
|
-
addRotationSchedule(id: string, options: RotationScheduleOptions): RotationSchedule;
|
|
38
|
-
addToResourcePolicy(statement: PolicyStatement): AddToResourcePolicyResult;
|
|
39
|
-
denyAccountRootDelete(): void;
|
|
40
|
-
attach(target: ISecretAttachmentTarget): ISecret;
|
|
41
|
-
cfnDynamicReferenceKey(options?: Parameters<ISecret["cfnDynamicReferenceKey"]>[0]): string;
|
|
42
|
-
get envKey(): string | undefined;
|
|
17
|
+
protected buildSecret(context: BuildSecretContext): secretsmanager.ISecret;
|
|
43
18
|
}
|
|
@@ -64,13 +64,14 @@ export interface JaypieLambdaProps {
|
|
|
64
64
|
/**
|
|
65
65
|
* Secrets to make available to the Lambda function.
|
|
66
66
|
*
|
|
67
|
-
* Supports both
|
|
68
|
-
* - JaypieEnvSecret: used directly
|
|
67
|
+
* Supports both JaypieSecret instances and strings:
|
|
68
|
+
* - JaypieSecret (including JaypieEnvSecret): used directly
|
|
69
69
|
* - String: creates a JaypieEnvSecret with the string as envKey
|
|
70
70
|
* (reuses existing secrets within the same scope)
|
|
71
71
|
*/
|
|
72
72
|
secrets?: SecretsArrayItem[];
|
|
73
73
|
securityGroups?: ec2.ISecurityGroup[];
|
|
74
|
+
serviceTag?: string;
|
|
74
75
|
timeout?: Duration | number;
|
|
75
76
|
tracing?: lambda.Tracing;
|
|
76
77
|
vendorTag?: string;
|
|
@@ -44,8 +44,8 @@ export interface JaypieNextjsProps {
|
|
|
44
44
|
/**
|
|
45
45
|
* Secrets to make available to the Next.js application.
|
|
46
46
|
*
|
|
47
|
-
* Supports both
|
|
48
|
-
* - JaypieEnvSecret: used directly
|
|
47
|
+
* Supports both JaypieSecret instances and strings:
|
|
48
|
+
* - JaypieSecret (including JaypieEnvSecret): used directly
|
|
49
49
|
* - String: creates a JaypieEnvSecret with the string as envKey
|
|
50
50
|
* (reuses existing secrets within the same scope)
|
|
51
51
|
*/
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Construct } from "constructs";
|
|
2
|
+
import { RemovalPolicy, SecretValue, Stack } from "aws-cdk-lib";
|
|
3
|
+
import * as secretsmanager from "aws-cdk-lib/aws-secretsmanager";
|
|
4
|
+
import { ISecret, ISecretAttachmentTarget, RotationSchedule, RotationScheduleOptions } from "aws-cdk-lib/aws-secretsmanager";
|
|
5
|
+
import { IKey } from "aws-cdk-lib/aws-kms";
|
|
6
|
+
import { AddToResourcePolicyResult, Grant, IGrantable, PolicyStatement } from "aws-cdk-lib/aws-iam";
|
|
7
|
+
export interface JaypieSecretProps {
|
|
8
|
+
envKey?: string;
|
|
9
|
+
generateSecretString?: secretsmanager.SecretStringGenerator;
|
|
10
|
+
removalPolicy?: boolean | RemovalPolicy;
|
|
11
|
+
roleTag?: string;
|
|
12
|
+
vendorTag?: string;
|
|
13
|
+
value?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Context handed to {@link JaypieSecret.buildSecret} so subclasses can build the
|
|
17
|
+
* underlying secret differently (e.g. import vs. create) while reusing the
|
|
18
|
+
* shared id/envKey resolution and the full ISecret passthrough.
|
|
19
|
+
*/
|
|
20
|
+
export interface BuildSecretContext {
|
|
21
|
+
envKey?: string;
|
|
22
|
+
id: string;
|
|
23
|
+
props: JaypieSecretProps;
|
|
24
|
+
treatAsEnvKey: boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare class JaypieSecret extends Construct implements ISecret {
|
|
27
|
+
protected static readonly shorthandPrefix: string;
|
|
28
|
+
protected readonly _envKey?: string;
|
|
29
|
+
protected readonly _secret: secretsmanager.ISecret;
|
|
30
|
+
constructor(scope: Construct, idOrEnvKey: string, props?: JaypieSecretProps);
|
|
31
|
+
/**
|
|
32
|
+
* Builds the underlying secret. The base implementation always creates a new
|
|
33
|
+
* Secrets Manager secret from an envKey value, an explicit value, or a
|
|
34
|
+
* generated string. Subclasses may override to import an existing secret or
|
|
35
|
+
* emit cross-stack outputs.
|
|
36
|
+
*/
|
|
37
|
+
protected buildSecret(context: BuildSecretContext): secretsmanager.ISecret;
|
|
38
|
+
get stack(): Stack;
|
|
39
|
+
get env(): {
|
|
40
|
+
account: string;
|
|
41
|
+
region: string;
|
|
42
|
+
};
|
|
43
|
+
applyRemovalPolicy(policy: RemovalPolicy): void;
|
|
44
|
+
get secretArn(): string;
|
|
45
|
+
get secretFullArn(): string | undefined;
|
|
46
|
+
get secretName(): string;
|
|
47
|
+
get secretRef(): secretsmanager.SecretReference;
|
|
48
|
+
get encryptionKey(): IKey | undefined;
|
|
49
|
+
get secretValue(): SecretValue;
|
|
50
|
+
secretValueFromJson(key: string): SecretValue;
|
|
51
|
+
grantRead(grantee: IGrantable, versionStages?: string[]): Grant;
|
|
52
|
+
grantWrite(grantee: IGrantable): Grant;
|
|
53
|
+
addRotationSchedule(id: string, options: RotationScheduleOptions): RotationSchedule;
|
|
54
|
+
addToResourcePolicy(statement: PolicyStatement): AddToResourcePolicyResult;
|
|
55
|
+
denyAccountRootDelete(): void;
|
|
56
|
+
attach(target: ISecretAttachmentTarget): ISecret;
|
|
57
|
+
cfnDynamicReferenceKey(options?: Parameters<ISecret["cfnDynamicReferenceKey"]>[0]): string;
|
|
58
|
+
get envKey(): string | undefined;
|
|
59
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { Construct } from "constructs";
|
|
2
|
-
import {
|
|
2
|
+
import { JaypieSecret } from "../JaypieSecret.js";
|
|
3
3
|
/**
|
|
4
|
-
* Secrets input type that supports both
|
|
5
|
-
* - JaypieEnvSecret: passed through as-is
|
|
6
|
-
* - string: converted to JaypieEnvSecret with the string as envKey
|
|
4
|
+
* Secrets input type that supports both JaypieSecret instances and strings
|
|
5
|
+
* - JaypieSecret (including JaypieEnvSecret subclasses): passed through as-is
|
|
6
|
+
* - string: converted to a JaypieEnvSecret with the string as envKey
|
|
7
7
|
*/
|
|
8
|
-
export type SecretsArrayItem =
|
|
8
|
+
export type SecretsArrayItem = JaypieSecret | string;
|
|
9
9
|
/**
|
|
10
|
-
* Resolves secrets input to an array of
|
|
10
|
+
* Resolves secrets input to an array of JaypieSecret instances.
|
|
11
11
|
*
|
|
12
|
-
* When an item is already a JaypieEnvSecret, it's
|
|
13
|
-
* When an item is a string, a JaypieEnvSecret is created
|
|
14
|
-
* with the string as the envKey.
|
|
12
|
+
* When an item is already a JaypieSecret (including a JaypieEnvSecret), it's
|
|
13
|
+
* passed through as-is. When an item is a string, a JaypieEnvSecret is created
|
|
14
|
+
* (or reused from cache) with the string as the envKey.
|
|
15
15
|
*
|
|
16
16
|
* Secrets are cached per scope to avoid creating duplicate secrets when
|
|
17
17
|
* multiple constructs in the same scope reference the same secret.
|
|
@@ -39,7 +39,7 @@ export type SecretsArrayItem = JaypieEnvSecret | string;
|
|
|
39
39
|
* const secrets2 = resolveSecrets(scope, ["SHARED_SECRET"]);
|
|
40
40
|
* // secrets1[0] === secrets2[0] (same instance)
|
|
41
41
|
*/
|
|
42
|
-
export declare function resolveSecrets(scope: Construct, secrets?: SecretsArrayItem[]):
|
|
42
|
+
export declare function resolveSecrets(scope: Construct, secrets?: SecretsArrayItem[]): JaypieSecret[];
|
|
43
43
|
/**
|
|
44
44
|
* Clears the secrets cache for a given scope.
|
|
45
45
|
* Primarily useful for testing.
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -973,115 +973,67 @@ const resolveParamsAndSecrets = ({ paramsAndSecrets, options, } = {}) => {
|
|
|
973
973
|
return resolvedParamsAndSecrets;
|
|
974
974
|
};
|
|
975
975
|
|
|
976
|
-
|
|
977
|
-
function checkEnvIsConsumer$1(env = process.env) {
|
|
978
|
-
return (env.PROJECT_ENV === CDK$2.ENV.PERSONAL ||
|
|
979
|
-
!!env.CDK_ENV_PERSONAL ||
|
|
980
|
-
/** @deprecated */ env.PROJECT_ENV === "ephemeral" ||
|
|
981
|
-
/** @deprecated */ !!env.CDK_ENV_EPHEMERAL);
|
|
982
|
-
}
|
|
983
|
-
function checkEnvIsProvider$1(env = process.env) {
|
|
984
|
-
return env.PROJECT_ENV === CDK$2.ENV.SANDBOX;
|
|
985
|
-
}
|
|
986
|
-
function cleanName$1(name) {
|
|
987
|
-
return name.replace(/[^a-zA-Z0-9:-]/g, "");
|
|
988
|
-
}
|
|
989
|
-
function exportEnvName$1(name, env = process.env, consumer = false) {
|
|
990
|
-
let rawName;
|
|
991
|
-
if (checkEnvIsProvider$1(env)) {
|
|
992
|
-
rawName = `env-${env.PROJECT_ENV}-${env.PROJECT_KEY}-${name}`;
|
|
993
|
-
// Clean the entire name to only allow alphanumeric, colons, and hyphens
|
|
994
|
-
return cleanName$1(rawName);
|
|
995
|
-
}
|
|
996
|
-
else {
|
|
997
|
-
if (consumer || checkEnvIsConsumer$1(env)) {
|
|
998
|
-
rawName = `env-${CDK$2.ENV.SANDBOX}-${env.PROJECT_KEY}-${name}`;
|
|
999
|
-
}
|
|
1000
|
-
else {
|
|
1001
|
-
rawName = `env-${env.PROJECT_ENV}-${env.PROJECT_KEY}-${name}`;
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
return cleanName$1(rawName);
|
|
1005
|
-
}
|
|
1006
|
-
class JaypieEnvSecret extends constructs.Construct {
|
|
976
|
+
class JaypieSecret extends constructs.Construct {
|
|
1007
977
|
constructor(scope, idOrEnvKey, props) {
|
|
1008
978
|
// Shorthand detection: treat idOrEnvKey as envKey when envKey prop is
|
|
1009
979
|
// not set and idOrEnvKey either looks like a SCREAMING_SNAKE_CASE env
|
|
1010
980
|
// var name or is already present in process.env. Convention-based
|
|
1011
981
|
// detection ensures missing env vars still go through envKey validation
|
|
1012
982
|
// instead of silently creating an empty secret.
|
|
983
|
+
const prefix = new.target.shorthandPrefix;
|
|
1013
984
|
const looksLikeEnvKey = /^[A-Z][A-Z0-9_]*$/.test(idOrEnvKey);
|
|
1014
985
|
const treatAsEnvKey = (!props || props.envKey === undefined) &&
|
|
1015
986
|
(looksLikeEnvKey ||
|
|
1016
987
|
(typeof process.env[idOrEnvKey] === "string" &&
|
|
1017
988
|
process.env[idOrEnvKey] !== ""));
|
|
1018
|
-
const id = treatAsEnvKey ?
|
|
989
|
+
const id = treatAsEnvKey ? `${prefix}${idOrEnvKey}` : idOrEnvKey;
|
|
1019
990
|
super(scope, id);
|
|
1020
|
-
const
|
|
1021
|
-
const envKey = treatAsEnvKey ? idOrEnvKey : envKeyProp;
|
|
991
|
+
const envKey = treatAsEnvKey ? idOrEnvKey : props?.envKey;
|
|
1022
992
|
this._envKey = envKey;
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
993
|
+
this._secret = this.buildSecret({
|
|
994
|
+
envKey,
|
|
995
|
+
id,
|
|
996
|
+
props: props || {},
|
|
997
|
+
treatAsEnvKey,
|
|
998
|
+
});
|
|
999
|
+
}
|
|
1000
|
+
/**
|
|
1001
|
+
* Builds the underlying secret. The base implementation always creates a new
|
|
1002
|
+
* Secrets Manager secret from an envKey value, an explicit value, or a
|
|
1003
|
+
* generated string. Subclasses may override to import an existing secret or
|
|
1004
|
+
* emit cross-stack outputs.
|
|
1005
|
+
*/
|
|
1006
|
+
buildSecret(context) {
|
|
1007
|
+
const { envKey, id, props } = context;
|
|
1008
|
+
const { generateSecretString, removalPolicy, roleTag, vendorTag, value } = props;
|
|
1009
|
+
if (envKey &&
|
|
1037
1010
|
!process.env[envKey] &&
|
|
1038
1011
|
value === undefined &&
|
|
1039
1012
|
!generateSecretString) {
|
|
1040
|
-
throw new errors.ConfigurationError(`
|
|
1013
|
+
throw new errors.ConfigurationError(`JaypieSecret(${id}): envKey "${envKey}" is empty in process.env and no value or generateSecretString was provided`);
|
|
1041
1014
|
}
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1015
|
+
const secretValue = envKey && process.env[envKey] ? process.env[envKey] : value;
|
|
1016
|
+
const secret = new secretsmanager__namespace.Secret(this, id, {
|
|
1017
|
+
generateSecretString,
|
|
1018
|
+
secretStringValue: !generateSecretString && secretValue
|
|
1019
|
+
? cdk.SecretValue.unsafePlainText(secretValue)
|
|
1020
|
+
: undefined,
|
|
1021
|
+
});
|
|
1022
|
+
if (removalPolicy !== undefined) {
|
|
1023
|
+
const policy = typeof removalPolicy === "boolean"
|
|
1024
|
+
? removalPolicy
|
|
1025
|
+
? cdk.RemovalPolicy.RETAIN
|
|
1026
|
+
: cdk.RemovalPolicy.DESTROY
|
|
1027
|
+
: removalPolicy;
|
|
1028
|
+
secret.applyRemovalPolicy(policy);
|
|
1049
1029
|
}
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
? cdk.SecretValue.unsafePlainText(secretValue)
|
|
1056
|
-
: undefined,
|
|
1057
|
-
};
|
|
1058
|
-
this._secret = new secretsmanager__namespace.Secret(this, id, secretProps);
|
|
1059
|
-
if (removalPolicy !== undefined) {
|
|
1060
|
-
const policy = typeof removalPolicy === "boolean"
|
|
1061
|
-
? removalPolicy
|
|
1062
|
-
? cdk.RemovalPolicy.RETAIN
|
|
1063
|
-
: cdk.RemovalPolicy.DESTROY
|
|
1064
|
-
: removalPolicy;
|
|
1065
|
-
this._secret.applyRemovalPolicy(policy);
|
|
1066
|
-
}
|
|
1067
|
-
if (roleTag) {
|
|
1068
|
-
cdk.Tags.of(this._secret).add(CDK$2.TAG.ROLE, roleTag);
|
|
1069
|
-
}
|
|
1070
|
-
if (vendorTag) {
|
|
1071
|
-
cdk.Tags.of(this._secret).add(CDK$2.TAG.VENDOR, vendorTag);
|
|
1072
|
-
}
|
|
1073
|
-
if (provider) {
|
|
1074
|
-
new cdk.CfnOutput(this, `ProvidedName`, {
|
|
1075
|
-
value: this._secret.secretName,
|
|
1076
|
-
exportName,
|
|
1077
|
-
});
|
|
1078
|
-
}
|
|
1079
|
-
else {
|
|
1080
|
-
new cdk.CfnOutput(this, `CreatedName`, {
|
|
1081
|
-
value: this._secret.secretName,
|
|
1082
|
-
});
|
|
1083
|
-
}
|
|
1030
|
+
if (roleTag) {
|
|
1031
|
+
cdk.Tags.of(secret).add(CDK$2.TAG.ROLE, roleTag);
|
|
1032
|
+
}
|
|
1033
|
+
if (vendorTag) {
|
|
1034
|
+
cdk.Tags.of(secret).add(CDK$2.TAG.VENDOR, vendorTag);
|
|
1084
1035
|
}
|
|
1036
|
+
return secret;
|
|
1085
1037
|
}
|
|
1086
1038
|
// IResource implementation
|
|
1087
1039
|
get stack() {
|
|
@@ -1143,6 +1095,117 @@ class JaypieEnvSecret extends constructs.Construct {
|
|
|
1143
1095
|
return this._envKey;
|
|
1144
1096
|
}
|
|
1145
1097
|
}
|
|
1098
|
+
// Construct id prefix used when an envKey is detected via shorthand.
|
|
1099
|
+
// Subclasses override this to preserve their own naming conventions.
|
|
1100
|
+
JaypieSecret.shorthandPrefix = "Secret_";
|
|
1101
|
+
|
|
1102
|
+
// It is a consumer if the environment is ephemeral
|
|
1103
|
+
function checkEnvIsConsumer$1(env = process.env) {
|
|
1104
|
+
return (env.PROJECT_ENV === CDK$2.ENV.PERSONAL ||
|
|
1105
|
+
!!env.CDK_ENV_PERSONAL ||
|
|
1106
|
+
/** @deprecated */ env.PROJECT_ENV === "ephemeral" ||
|
|
1107
|
+
/** @deprecated */ !!env.CDK_ENV_EPHEMERAL);
|
|
1108
|
+
}
|
|
1109
|
+
function checkEnvIsProvider$1(env = process.env) {
|
|
1110
|
+
return env.PROJECT_ENV === CDK$2.ENV.SANDBOX;
|
|
1111
|
+
}
|
|
1112
|
+
function cleanName$1(name) {
|
|
1113
|
+
return name.replace(/[^a-zA-Z0-9:-]/g, "");
|
|
1114
|
+
}
|
|
1115
|
+
function exportEnvName$1(name, env = process.env, consumer = false) {
|
|
1116
|
+
let rawName;
|
|
1117
|
+
if (checkEnvIsProvider$1(env)) {
|
|
1118
|
+
rawName = `env-${env.PROJECT_ENV}-${env.PROJECT_KEY}-${name}`;
|
|
1119
|
+
// Clean the entire name to only allow alphanumeric, colons, and hyphens
|
|
1120
|
+
return cleanName$1(rawName);
|
|
1121
|
+
}
|
|
1122
|
+
else {
|
|
1123
|
+
if (consumer || checkEnvIsConsumer$1(env)) {
|
|
1124
|
+
rawName = `env-${CDK$2.ENV.SANDBOX}-${env.PROJECT_KEY}-${name}`;
|
|
1125
|
+
}
|
|
1126
|
+
else {
|
|
1127
|
+
rawName = `env-${env.PROJECT_ENV}-${env.PROJECT_KEY}-${name}`;
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
return cleanName$1(rawName);
|
|
1131
|
+
}
|
|
1132
|
+
/**
|
|
1133
|
+
* @deprecated Use {@link JaypieSecret}. JaypieEnvSecret layers an
|
|
1134
|
+
* environment-driven provider/consumer cross-stack pattern on top of
|
|
1135
|
+
* JaypieSecret and will be removed in 2.0.
|
|
1136
|
+
*/
|
|
1137
|
+
class JaypieEnvSecret extends JaypieSecret {
|
|
1138
|
+
constructor(scope, idOrEnvKey, props) {
|
|
1139
|
+
super(scope, idOrEnvKey, props);
|
|
1140
|
+
}
|
|
1141
|
+
buildSecret(context) {
|
|
1142
|
+
const { envKey, id, treatAsEnvKey } = context;
|
|
1143
|
+
const props = context.props;
|
|
1144
|
+
const { consumer = checkEnvIsConsumer$1(), export: exportParam, generateSecretString, provider = checkEnvIsProvider$1(), removalPolicy, roleTag, vendorTag, value, } = props;
|
|
1145
|
+
let exportName;
|
|
1146
|
+
if (!exportParam) {
|
|
1147
|
+
// When shorthand detection is active, use the full construct id (which
|
|
1148
|
+
// includes the "EnvSecret_" prefix) so the export name matches what was
|
|
1149
|
+
// produced by earlier versions of this construct. Using the raw envKey
|
|
1150
|
+
// here produces a shorter name that breaks existing cross-stack imports.
|
|
1151
|
+
const exportSource = treatAsEnvKey ? id : envKey || id;
|
|
1152
|
+
exportName = exportEnvName$1(exportSource, process.env, consumer);
|
|
1153
|
+
}
|
|
1154
|
+
else {
|
|
1155
|
+
exportName = cleanName$1(exportParam);
|
|
1156
|
+
}
|
|
1157
|
+
if (!consumer &&
|
|
1158
|
+
envKey &&
|
|
1159
|
+
!process.env[envKey] &&
|
|
1160
|
+
value === undefined &&
|
|
1161
|
+
!generateSecretString) {
|
|
1162
|
+
throw new errors.ConfigurationError(`JaypieEnvSecret(${id}): envKey "${envKey}" is empty in process.env and no value or generateSecretString was provided`);
|
|
1163
|
+
}
|
|
1164
|
+
if (consumer) {
|
|
1165
|
+
const secretName = cdk.Fn.importValue(exportName);
|
|
1166
|
+
const secret = secretsmanager__namespace.Secret.fromSecretNameV2(this, id, secretName);
|
|
1167
|
+
// Add CfnOutput for consumer secrets
|
|
1168
|
+
new cdk.CfnOutput(this, `ConsumedName`, {
|
|
1169
|
+
value: secret.secretName,
|
|
1170
|
+
});
|
|
1171
|
+
return secret;
|
|
1172
|
+
}
|
|
1173
|
+
const secretValue = envKey && process.env[envKey] ? process.env[envKey] : value;
|
|
1174
|
+
const secret = new secretsmanager__namespace.Secret(this, id, {
|
|
1175
|
+
generateSecretString,
|
|
1176
|
+
secretStringValue: !generateSecretString && secretValue
|
|
1177
|
+
? cdk.SecretValue.unsafePlainText(secretValue)
|
|
1178
|
+
: undefined,
|
|
1179
|
+
});
|
|
1180
|
+
if (removalPolicy !== undefined) {
|
|
1181
|
+
const policy = typeof removalPolicy === "boolean"
|
|
1182
|
+
? removalPolicy
|
|
1183
|
+
? cdk.RemovalPolicy.RETAIN
|
|
1184
|
+
: cdk.RemovalPolicy.DESTROY
|
|
1185
|
+
: removalPolicy;
|
|
1186
|
+
secret.applyRemovalPolicy(policy);
|
|
1187
|
+
}
|
|
1188
|
+
if (roleTag) {
|
|
1189
|
+
cdk.Tags.of(secret).add(CDK$2.TAG.ROLE, roleTag);
|
|
1190
|
+
}
|
|
1191
|
+
if (vendorTag) {
|
|
1192
|
+
cdk.Tags.of(secret).add(CDK$2.TAG.VENDOR, vendorTag);
|
|
1193
|
+
}
|
|
1194
|
+
if (provider) {
|
|
1195
|
+
new cdk.CfnOutput(this, `ProvidedName`, {
|
|
1196
|
+
value: secret.secretName,
|
|
1197
|
+
exportName,
|
|
1198
|
+
});
|
|
1199
|
+
}
|
|
1200
|
+
else {
|
|
1201
|
+
new cdk.CfnOutput(this, `CreatedName`, {
|
|
1202
|
+
value: secret.secretName,
|
|
1203
|
+
});
|
|
1204
|
+
}
|
|
1205
|
+
return secret;
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
JaypieEnvSecret.shorthandPrefix = "EnvSecret_";
|
|
1146
1209
|
|
|
1147
1210
|
/**
|
|
1148
1211
|
* Cache for secrets by scope to avoid creating duplicates.
|
|
@@ -1179,11 +1242,11 @@ function getOrCreateSecret(scope, envKey, props) {
|
|
|
1179
1242
|
return secret;
|
|
1180
1243
|
}
|
|
1181
1244
|
/**
|
|
1182
|
-
* Resolves secrets input to an array of
|
|
1245
|
+
* Resolves secrets input to an array of JaypieSecret instances.
|
|
1183
1246
|
*
|
|
1184
|
-
* When an item is already a JaypieEnvSecret, it's
|
|
1185
|
-
* When an item is a string, a JaypieEnvSecret is created
|
|
1186
|
-
* with the string as the envKey.
|
|
1247
|
+
* When an item is already a JaypieSecret (including a JaypieEnvSecret), it's
|
|
1248
|
+
* passed through as-is. When an item is a string, a JaypieEnvSecret is created
|
|
1249
|
+
* (or reused from cache) with the string as the envKey.
|
|
1187
1250
|
*
|
|
1188
1251
|
* Secrets are cached per scope to avoid creating duplicate secrets when
|
|
1189
1252
|
* multiple constructs in the same scope reference the same secret.
|
|
@@ -1219,7 +1282,7 @@ function resolveSecrets(scope, secrets) {
|
|
|
1219
1282
|
if (typeof item === "string") {
|
|
1220
1283
|
return getOrCreateSecret(scope, item);
|
|
1221
1284
|
}
|
|
1222
|
-
// Already a JaypieEnvSecret instance
|
|
1285
|
+
// Already a JaypieSecret (or JaypieEnvSecret) instance
|
|
1223
1286
|
return item;
|
|
1224
1287
|
});
|
|
1225
1288
|
}
|
|
@@ -1429,12 +1492,12 @@ class JaypieLambda extends constructs.Construct {
|
|
|
1429
1492
|
super(scope, id);
|
|
1430
1493
|
const { allowAllOutbound, allowPublicSubnet, architecture = lambda__namespace.Architecture.X86_64, code, datadogApiKeyArn, deadLetterQueue, deadLetterQueueEnabled, deadLetterTopic, description, tables = [], environment: environmentInput, envSecrets = {}, ephemeralStorageSize, filesystem, handler = "index.handler", initialPolicy, layers = [], logGroup, logRetention = CDK$2.LAMBDA.LOG_RETENTION, maxEventAge, memorySize = CDK$2.LAMBDA.MEMORY_SIZE, paramsAndSecrets, paramsAndSecretsOptions, profiling, profilingGroup, provisionedConcurrentExecutions, reservedConcurrentExecutions, retryAttempts, roleTag = CDK$2.ROLE.PROCESSING, runtime = new lambda__namespace.Runtime("nodejs24.x", lambda__namespace.RuntimeFamily.NODEJS, {
|
|
1431
1494
|
supportsInlineCode: true,
|
|
1432
|
-
}), runtimeManagementMode, secrets: secretsInput = [], securityGroups, timeout = cdk.Duration.seconds(CDK$2.DURATION.LAMBDA_WORKER), tracing, vendorTag, vpc, vpcSubnets, } = props;
|
|
1495
|
+
}), runtimeManagementMode, secrets: secretsInput = [], securityGroups, serviceTag, timeout = cdk.Duration.seconds(CDK$2.DURATION.LAMBDA_WORKER), tracing, vendorTag, vpc, vpcSubnets, } = props;
|
|
1433
1496
|
// Resolve environment from array or object syntax
|
|
1434
1497
|
const initialEnvironment = resolveEnvironment(environmentInput);
|
|
1435
1498
|
// Get base environment with defaults
|
|
1436
1499
|
const environment = jaypieLambdaEnv({ initialEnvironment });
|
|
1437
|
-
// Resolve secrets from mixed array (strings and
|
|
1500
|
+
// Resolve secrets from mixed array (strings and JaypieSecret instances)
|
|
1438
1501
|
// Use Stack.of(this) to ensure secrets are shared at stack level across all constructs
|
|
1439
1502
|
const secrets = resolveSecrets(cdk.Stack.of(this), secretsInput);
|
|
1440
1503
|
const codeAsset = typeof code === "string" ? lambda__namespace.Code.fromAsset(code) : code;
|
|
@@ -1445,7 +1508,7 @@ class JaypieLambda extends constructs.Construct {
|
|
|
1445
1508
|
...acc,
|
|
1446
1509
|
[`SECRET_${key}`]: secret.secretName,
|
|
1447
1510
|
}), {});
|
|
1448
|
-
// Process
|
|
1511
|
+
// Process JaypieSecret array
|
|
1449
1512
|
const jaypieSecretsEnvironment = secrets.reduce((acc, secret) => {
|
|
1450
1513
|
if (secret.envKey) {
|
|
1451
1514
|
return {
|
|
@@ -1515,7 +1578,7 @@ class JaypieLambda extends constructs.Construct {
|
|
|
1515
1578
|
Object.values(envSecrets).forEach((secret) => {
|
|
1516
1579
|
secret.grantRead(this._lambda);
|
|
1517
1580
|
});
|
|
1518
|
-
// Grant read permissions for
|
|
1581
|
+
// Grant read permissions for JaypieSecrets
|
|
1519
1582
|
secrets.forEach((secret) => {
|
|
1520
1583
|
secret.grantRead(this._lambda);
|
|
1521
1584
|
});
|
|
@@ -1543,6 +1606,9 @@ class JaypieLambda extends constructs.Construct {
|
|
|
1543
1606
|
if (roleTag) {
|
|
1544
1607
|
cdk.Tags.of(this._lambda).add(CDK$2.TAG.ROLE, roleTag);
|
|
1545
1608
|
}
|
|
1609
|
+
if (serviceTag) {
|
|
1610
|
+
cdk.Tags.of(this._lambda).add(CDK$2.TAG.SERVICE, serviceTag);
|
|
1611
|
+
}
|
|
1546
1612
|
if (vendorTag) {
|
|
1547
1613
|
cdk.Tags.of(this._lambda).add(CDK$2.TAG.VENDOR, vendorTag);
|
|
1548
1614
|
}
|
|
@@ -1667,7 +1733,7 @@ class JaypieQueuedLambda extends constructs.Construct {
|
|
|
1667
1733
|
super(scope, id);
|
|
1668
1734
|
const { allowAllOutbound, allowPublicSubnet, architecture, batchSize = 1, code, datadogApiKeyArn, deadLetterQueue, deadLetterQueueEnabled, deadLetterTopic, description, environment = {}, envSecrets = {}, ephemeralStorageSize, fifo = true, filesystem, handler = "index.handler", initialPolicy, layers = [], logGroup, logRetention = CDK$2.LAMBDA.LOG_RETENTION, maxEventAge, memorySize = CDK$2.LAMBDA.MEMORY_SIZE, paramsAndSecrets, paramsAndSecretsOptions, profiling, profilingGroup, provisionedConcurrentExecutions, reservedConcurrentExecutions, retryAttempts, roleTag, runtime = new lambda__namespace.Runtime("nodejs24.x", lambda__namespace.RuntimeFamily.NODEJS, {
|
|
1669
1735
|
supportsInlineCode: true,
|
|
1670
|
-
}), runtimeManagementMode, secrets = [], securityGroups, tables = [], timeout = cdk.Duration.seconds(CDK$2.DURATION.LAMBDA_WORKER), tracing, vendorTag, visibilityTimeout = cdk.Duration.seconds(CDK$2.DURATION.LAMBDA_WORKER), vpc, vpcSubnets, } = props;
|
|
1736
|
+
}), runtimeManagementMode, secrets = [], securityGroups, serviceTag, tables = [], timeout = cdk.Duration.seconds(CDK$2.DURATION.LAMBDA_WORKER), tracing, vendorTag, visibilityTimeout = cdk.Duration.seconds(CDK$2.DURATION.LAMBDA_WORKER), vpc, vpcSubnets, } = props;
|
|
1671
1737
|
// Create SQS Queue
|
|
1672
1738
|
this._queue = new sqs__namespace.Queue(this, "Queue", {
|
|
1673
1739
|
fifo,
|
|
@@ -1678,6 +1744,9 @@ class JaypieQueuedLambda extends constructs.Construct {
|
|
|
1678
1744
|
if (roleTag) {
|
|
1679
1745
|
cdk.Tags.of(this._queue).add(CDK$2.TAG.ROLE, roleTag);
|
|
1680
1746
|
}
|
|
1747
|
+
if (serviceTag) {
|
|
1748
|
+
cdk.Tags.of(this._queue).add(CDK$2.TAG.SERVICE, serviceTag);
|
|
1749
|
+
}
|
|
1681
1750
|
if (vendorTag) {
|
|
1682
1751
|
cdk.Tags.of(this._queue).add(CDK$2.TAG.VENDOR, vendorTag);
|
|
1683
1752
|
}
|
|
@@ -1715,6 +1784,7 @@ class JaypieQueuedLambda extends constructs.Construct {
|
|
|
1715
1784
|
runtimeManagementMode,
|
|
1716
1785
|
secrets,
|
|
1717
1786
|
securityGroups,
|
|
1787
|
+
serviceTag,
|
|
1718
1788
|
tables,
|
|
1719
1789
|
timeout,
|
|
1720
1790
|
tracing,
|
|
@@ -1909,7 +1979,7 @@ class JaypieBucketQueuedLambda extends JaypieQueuedLambda {
|
|
|
1909
1979
|
constructor(scope, id, props) {
|
|
1910
1980
|
props.fifo = false; // S3 event notifications are not supported for FIFO queues
|
|
1911
1981
|
super(scope, id, props);
|
|
1912
|
-
const { bucketName, roleTag, vendorTag, bucketOptions = {} } = props;
|
|
1982
|
+
const { bucketName, roleTag, serviceTag, vendorTag, bucketOptions = {}, } = props;
|
|
1913
1983
|
// Create S3 Bucket
|
|
1914
1984
|
this._bucket = new s3__namespace.Bucket(this, "Bucket", {
|
|
1915
1985
|
bucketName: bucketOptions.bucketName || bucketName,
|
|
@@ -1920,6 +1990,9 @@ class JaypieBucketQueuedLambda extends JaypieQueuedLambda {
|
|
|
1920
1990
|
if (roleTag) {
|
|
1921
1991
|
cdk.Tags.of(this._bucket).add(CDK$2.TAG.ROLE, roleTag);
|
|
1922
1992
|
}
|
|
1993
|
+
if (serviceTag) {
|
|
1994
|
+
cdk.Tags.of(this._bucket).add(CDK$2.TAG.SERVICE, serviceTag);
|
|
1995
|
+
}
|
|
1923
1996
|
if (vendorTag) {
|
|
1924
1997
|
cdk.Tags.of(this._bucket).add(CDK$2.TAG.VENDOR, vendorTag);
|
|
1925
1998
|
}
|
|
@@ -3757,7 +3830,7 @@ class JaypieNextJs extends constructs.Construct {
|
|
|
3757
3830
|
? path__namespace.join(process.cwd(), props.nextjsPath)
|
|
3758
3831
|
: props?.nextjsPath || path__namespace.join(process.cwd(), "..", "nextjs");
|
|
3759
3832
|
const paramsAndSecrets = resolveParamsAndSecrets();
|
|
3760
|
-
// Resolve secrets from mixed array (strings and
|
|
3833
|
+
// Resolve secrets from mixed array (strings and JaypieSecret instances)
|
|
3761
3834
|
// Use Stack.of(this) to ensure secrets are shared at stack level across all constructs
|
|
3762
3835
|
const secrets = resolveSecrets(cdk.Stack.of(this), props?.secrets);
|
|
3763
3836
|
// Process secrets environment variables
|
|
@@ -3765,7 +3838,7 @@ class JaypieNextJs extends constructs.Construct {
|
|
|
3765
3838
|
...acc,
|
|
3766
3839
|
[`SECRET_${key}`]: secret.secretName,
|
|
3767
3840
|
}), {});
|
|
3768
|
-
// Process
|
|
3841
|
+
// Process JaypieSecret array
|
|
3769
3842
|
const jaypieSecretsEnvironment = secrets.reduce((acc, secret) => {
|
|
3770
3843
|
if (secret.envKey) {
|
|
3771
3844
|
return {
|
|
@@ -3840,7 +3913,7 @@ class JaypieNextJs extends constructs.Construct {
|
|
|
3840
3913
|
Object.values(envSecrets).forEach((secret) => {
|
|
3841
3914
|
secret.grantRead(nextjs.serverFunction.lambdaFunction);
|
|
3842
3915
|
});
|
|
3843
|
-
// Grant read permissions for
|
|
3916
|
+
// Grant read permissions for JaypieSecrets
|
|
3844
3917
|
secrets.forEach((secret) => {
|
|
3845
3918
|
secret.grantRead(nextjs.serverFunction.lambdaFunction);
|
|
3846
3919
|
});
|
|
@@ -4204,6 +4277,9 @@ class JaypieSsoPermissions extends constructs.Construct {
|
|
|
4204
4277
|
{
|
|
4205
4278
|
Effect: "Allow",
|
|
4206
4279
|
Action: [
|
|
4280
|
+
"bedrock-agent:*",
|
|
4281
|
+
"bedrock-agentcore:*",
|
|
4282
|
+
"bedrock:*",
|
|
4207
4283
|
"budgets:*",
|
|
4208
4284
|
"ce:*",
|
|
4209
4285
|
"cloudformation:*",
|
|
@@ -5404,6 +5480,7 @@ exports.JaypieNextJs = JaypieNextJs;
|
|
|
5404
5480
|
exports.JaypieOpenAiSecret = JaypieOpenAiSecret;
|
|
5405
5481
|
exports.JaypieOrganizationTrail = JaypieOrganizationTrail;
|
|
5406
5482
|
exports.JaypieQueuedLambda = JaypieQueuedLambda;
|
|
5483
|
+
exports.JaypieSecret = JaypieSecret;
|
|
5407
5484
|
exports.JaypieSsoPermissions = JaypieSsoPermissions;
|
|
5408
5485
|
exports.JaypieSsoSyncApplication = JaypieSsoSyncApplication;
|
|
5409
5486
|
exports.JaypieStack = JaypieStack;
|