@jaypie/constructs 1.1.48 → 1.1.50

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.
Files changed (45) hide show
  1. package/dist/cjs/JaypieApiGateway.d.ts +1 -0
  2. package/dist/cjs/JaypieBucketQueuedLambda.d.ts +4 -19
  3. package/dist/cjs/JaypieDnsRecord.d.ts +45 -0
  4. package/dist/cjs/JaypieGitHubDeployRole.d.ts +15 -0
  5. package/dist/cjs/JaypieHostedZone.d.ts +26 -4
  6. package/dist/cjs/JaypieLambda.d.ts +1 -1
  7. package/dist/cjs/JaypieQueuedLambda.d.ts +1 -1
  8. package/dist/cjs/JaypieSsoPermissions.d.ts +95 -0
  9. package/dist/cjs/JaypieSsoSyncApplication.d.ts +27 -0
  10. package/dist/cjs/JaypieWebDeploymentBucket.d.ts +1 -0
  11. package/dist/cjs/__tests__/JaypieSsoSyncApplication.spec.d.ts +1 -0
  12. package/dist/cjs/helpers/__tests__/resolveDatadogForwarderFunction.spec.d.ts +1 -0
  13. package/dist/cjs/helpers/__tests__/resolveDatadogLoggingDestination.spec.d.ts +1 -0
  14. package/dist/cjs/helpers/index.d.ts +2 -0
  15. package/dist/cjs/helpers/resolveDatadogForwarderFunction.d.ts +7 -0
  16. package/dist/cjs/helpers/resolveDatadogLoggingDestination.d.ts +4 -0
  17. package/dist/cjs/index.cjs +599 -308
  18. package/dist/cjs/index.cjs.map +1 -1
  19. package/dist/cjs/index.d.ts +6 -2
  20. package/dist/esm/JaypieApiGateway.d.ts +1 -0
  21. package/dist/esm/JaypieBucketQueuedLambda.d.ts +4 -19
  22. package/dist/esm/JaypieDnsRecord.d.ts +45 -0
  23. package/dist/esm/JaypieGitHubDeployRole.d.ts +15 -0
  24. package/dist/esm/JaypieHostedZone.d.ts +26 -4
  25. package/dist/esm/JaypieLambda.d.ts +1 -1
  26. package/dist/esm/JaypieQueuedLambda.d.ts +1 -1
  27. package/dist/esm/JaypieSsoPermissions.d.ts +95 -0
  28. package/dist/esm/JaypieSsoSyncApplication.d.ts +27 -0
  29. package/dist/esm/JaypieWebDeploymentBucket.d.ts +1 -0
  30. package/dist/esm/__tests__/JaypieDnsRecord.spec.d.ts +1 -0
  31. package/dist/esm/__tests__/JaypieSsoPermissions.spec.d.ts +1 -0
  32. package/dist/esm/__tests__/JaypieSsoSyncApplication.spec.d.ts +1 -0
  33. package/dist/esm/helpers/__tests__/resolveDatadogForwarderFunction.spec.d.ts +1 -0
  34. package/dist/esm/helpers/__tests__/resolveDatadogLoggingDestination.spec.d.ts +1 -0
  35. package/dist/esm/helpers/index.d.ts +2 -0
  36. package/dist/esm/helpers/resolveDatadogForwarderFunction.d.ts +7 -0
  37. package/dist/esm/helpers/resolveDatadogLoggingDestination.d.ts +4 -0
  38. package/dist/esm/index.d.ts +6 -2
  39. package/dist/esm/index.js +592 -309
  40. package/dist/esm/index.js.map +1 -1
  41. package/package.json +3 -2
  42. package/dist/cjs/JaypieSsoGroups.d.ts +0 -121
  43. package/dist/esm/JaypieSsoGroups.d.ts +0 -121
  44. /package/dist/cjs/__tests__/{JaypieSsoGroups.spec.d.ts → JaypieDnsRecord.spec.d.ts} +0 -0
  45. /package/dist/{esm/__tests__/JaypieSsoGroups.spec.d.ts → cjs/__tests__/JaypieSsoPermissions.spec.d.ts} +0 -0
@@ -1,22 +1,25 @@
1
1
  'use strict';
2
2
 
3
+ var cdk = require('@jaypie/cdk');
3
4
  var constructs = require('constructs');
4
5
  var cdk$1 = require('aws-cdk-lib');
5
6
  var acm = require('aws-cdk-lib/aws-certificatemanager');
6
7
  var apiGateway = require('aws-cdk-lib/aws-apigateway');
7
8
  var route53 = require('aws-cdk-lib/aws-route53');
8
9
  var route53Targets = require('aws-cdk-lib/aws-route53-targets');
9
- var cdk = require('@jaypie/cdk');
10
10
  var secretsmanager = require('aws-cdk-lib/aws-secretsmanager');
11
11
  var datadogCdkConstructsV2 = require('datadog-cdk-constructs-v2');
12
12
  var lambda = require('aws-cdk-lib/aws-lambda');
13
+ var logDestinations = require('aws-cdk-lib/aws-logs-destinations');
13
14
  var s3 = require('aws-cdk-lib/aws-s3');
14
15
  var s3n = require('aws-cdk-lib/aws-s3-notifications');
15
16
  var sqs = require('aws-cdk-lib/aws-sqs');
16
17
  var lambdaEventSources = require('aws-cdk-lib/aws-lambda-event-sources');
17
18
  var awsIam = require('aws-cdk-lib/aws-iam');
18
19
  var awsLogs = require('aws-cdk-lib/aws-logs');
19
- var sso = require('aws-cdk-lib/aws-sso');
20
+ var awsSso = require('aws-cdk-lib/aws-sso');
21
+ var awsSam = require('aws-cdk-lib/aws-sam');
22
+ var errors = require('@jaypie/errors');
20
23
  var cloudfront = require('aws-cdk-lib/aws-cloudfront');
21
24
  var origins = require('aws-cdk-lib/aws-cloudfront-origins');
22
25
 
@@ -44,11 +47,11 @@ var route53__namespace = /*#__PURE__*/_interopNamespaceDefault(route53);
44
47
  var route53Targets__namespace = /*#__PURE__*/_interopNamespaceDefault(route53Targets);
45
48
  var secretsmanager__namespace = /*#__PURE__*/_interopNamespaceDefault(secretsmanager);
46
49
  var lambda__namespace = /*#__PURE__*/_interopNamespaceDefault(lambda);
50
+ var logDestinations__namespace = /*#__PURE__*/_interopNamespaceDefault(logDestinations);
47
51
  var s3__namespace = /*#__PURE__*/_interopNamespaceDefault(s3);
48
52
  var s3n__namespace = /*#__PURE__*/_interopNamespaceDefault(s3n);
49
53
  var sqs__namespace = /*#__PURE__*/_interopNamespaceDefault(sqs);
50
54
  var lambdaEventSources__namespace = /*#__PURE__*/_interopNamespaceDefault(lambdaEventSources);
51
- var sso__namespace = /*#__PURE__*/_interopNamespaceDefault(sso);
52
55
  var cloudfront__namespace = /*#__PURE__*/_interopNamespaceDefault(cloudfront);
53
56
  var origins__namespace = /*#__PURE__*/_interopNamespaceDefault(origins);
54
57
 
@@ -247,6 +250,33 @@ function jaypieLambdaEnv(options = {}) {
247
250
  return environment;
248
251
  }
249
252
 
253
+ const DEFAULT_FUNCTION_NAME$1 = "DatadogForwarderFunction";
254
+ // Cache to store resolved functions
255
+ // Using nested structure to support multiple functions per scope with automatic GC
256
+ const functionCache = new WeakMap();
257
+ function resolveDatadogForwarderFunction(scope, options) {
258
+ const { import: importValue, name } = options || {};
259
+ const functionName = name || DEFAULT_FUNCTION_NAME$1;
260
+ const importKey = importValue || cdk.CDK.IMPORT.DATADOG_LOG_FORWARDER;
261
+ // Create a cache key based on name and import
262
+ const cacheKey = `${functionName}:${importKey}`;
263
+ // Get or create scope cache
264
+ let scopeCache = functionCache.get(scope);
265
+ if (!scopeCache) {
266
+ scopeCache = new Map();
267
+ functionCache.set(scope, scopeCache);
268
+ }
269
+ // Return cached function if it exists
270
+ const cachedFunction = scopeCache.get(cacheKey);
271
+ if (cachedFunction) {
272
+ return cachedFunction;
273
+ }
274
+ // Create and cache the function
275
+ const func = lambda__namespace.Function.fromFunctionArn(scope, functionName, cdk__namespace.Fn.importValue(importKey));
276
+ scopeCache.set(cacheKey, func);
277
+ return func;
278
+ }
279
+
250
280
  function resolveDatadogLayers(scope, options = {}) {
251
281
  const { datadogApiKeyArn, uniqueId } = options;
252
282
  let resolvedRegion = cdk$1.Stack.of(scope).region || "us-east-1";
@@ -266,6 +296,35 @@ function resolveDatadogLayers(scope, options = {}) {
266
296
  return [datadogNodeLayer, datadogExtensionLayer];
267
297
  }
268
298
 
299
+ const DEFAULT_FUNCTION_NAME = "DatadogForwarderFunction";
300
+ // Cache to store resolved logging destinations
301
+ // Using nested structure to support multiple destinations per scope with automatic GC
302
+ const destinationCache = new WeakMap();
303
+ function resolveDatadogLoggingDestination(scope, options) {
304
+ const { import: importValue, name } = options || {};
305
+ // Create a cache key based on name and import (same as forwarder function)
306
+ const functionName = name || DEFAULT_FUNCTION_NAME;
307
+ const importKey = importValue || cdk.CDK.IMPORT.DATADOG_LOG_FORWARDER;
308
+ const cacheKey = `${functionName}:${importKey}`;
309
+ // Get or create scope cache
310
+ let scopeCache = destinationCache.get(scope);
311
+ if (!scopeCache) {
312
+ scopeCache = new Map();
313
+ destinationCache.set(scope, scopeCache);
314
+ }
315
+ // Return cached destination if it exists
316
+ const cachedDestination = scopeCache.get(cacheKey);
317
+ if (cachedDestination) {
318
+ return cachedDestination;
319
+ }
320
+ // Resolve the Datadog forwarder function
321
+ const datadogForwarderFunction = resolveDatadogForwarderFunction(scope, options);
322
+ // Create and cache the logging destination
323
+ const datadogLoggingDestination = new logDestinations__namespace.LambdaDestination(datadogForwarderFunction);
324
+ scopeCache.set(cacheKey, datadogLoggingDestination);
325
+ return datadogLoggingDestination;
326
+ }
327
+
269
328
  function resolveHostedZone(scope, { name = "HostedZone", zone = process.env.CDK_ENV_HOSTED_ZONE, } = {}) {
270
329
  if (!zone) {
271
330
  throw new cdk.ConfigurationError("No `zone` provided. Set CDK_ENV_HOSTED_ZONE to use environment zone");
@@ -439,6 +498,11 @@ class JaypieApiGateway extends constructs.Construct {
439
498
  applyRemovalPolicy(policy) {
440
499
  this._api.applyRemovalPolicy(policy);
441
500
  }
501
+ get restApiRef() {
502
+ return {
503
+ restApiId: this._api.restApiId,
504
+ };
505
+ }
442
506
  }
443
507
 
444
508
  class JaypieStack extends cdk$1.Stack {
@@ -620,7 +684,10 @@ class JaypieLambda extends constructs.Construct {
620
684
  return this._reference.resourceArnsForGrantInvoke;
621
685
  }
622
686
  get functionRef() {
623
- return this._reference.functionRef;
687
+ return {
688
+ functionArn: this._reference.functionArn,
689
+ functionName: this._reference.functionName,
690
+ };
624
691
  }
625
692
  addEventSource(source) {
626
693
  this._reference.addEventSource(source);
@@ -982,7 +1049,7 @@ class JaypieBucketQueuedLambda extends JaypieQueuedLambda {
982
1049
  get policy() {
983
1050
  return this._bucket.policy;
984
1051
  }
985
- addEventNotification(event, dest, filters) {
1052
+ addEventNotification(event, dest, ...filters) {
986
1053
  this._bucket.addEventNotification(event, dest, ...filters);
987
1054
  }
988
1055
  addObjectCreatedNotification(dest, ...filters) {
@@ -1000,9 +1067,6 @@ class JaypieBucketQueuedLambda extends JaypieQueuedLambda {
1000
1067
  enableEventBridgeNotification() {
1001
1068
  this._bucket.enableEventBridgeNotification();
1002
1069
  }
1003
- grant(grantee, ...actions) {
1004
- return this._bucket.grant(grantee, ...actions);
1005
- }
1006
1070
  grantDelete(grantee, objectsKeyPattern) {
1007
1071
  return this._bucket.grantDelete(grantee, objectsKeyPattern);
1008
1072
  }
@@ -1045,54 +1109,17 @@ class JaypieBucketQueuedLambda extends JaypieQueuedLambda {
1045
1109
  virtualHostedUrlForObject(key, options) {
1046
1110
  return this._bucket.virtualHostedUrlForObject(key, options);
1047
1111
  }
1048
- // Bucket metrics
1049
- metricAllRequests(props) {
1050
- return this._bucket.metricAllRequests(props);
1051
- }
1052
- metricBucketSizeBytes(props) {
1053
- return this._bucket.metricBucketSizeBytes(props);
1054
- }
1055
- metricDeleteRequests(props) {
1056
- return this._bucket.metricDeleteRequests(props);
1057
- }
1058
- metricDownloadBytes(props) {
1059
- return this._bucket.metricDownloadBytes(props);
1060
- }
1061
- metricFirstByteLatency(props) {
1062
- return this._bucket.metricFirstByteLatency(props);
1063
- }
1064
- metricGetRequests(props) {
1065
- return this._bucket.metricGetRequests(props);
1066
- }
1067
- metricHeadRequests(props) {
1068
- return this._bucket.metricHeadRequests(props);
1069
- }
1070
- metricHttpRequests(props) {
1071
- return this._bucket.metricHttpRequests(props);
1072
- }
1073
- metricListRequests(props) {
1074
- return this._bucket.metricListRequests(props);
1075
- }
1076
- metricNumberOfObjects(props) {
1077
- return this._bucket.metricNumberOfObjects(props);
1078
- }
1079
- metricPostRequests(props) {
1080
- return this._bucket.metricPostRequests(props);
1081
- }
1082
- metricPutRequests(props) {
1083
- return this._bucket.metricPutRequests(props);
1084
- }
1085
- metricSelectRequests(props) {
1086
- return this._bucket.metricSelectRequests(props);
1087
- }
1088
- metricSelectScannedBytes(props) {
1089
- return this._bucket.metricSelectScannedBytes(props);
1112
+ grantReplicationPermission(identity, props) {
1113
+ return this._bucket.grantReplicationPermission(identity, props);
1090
1114
  }
1091
- metricUploadBytes(props) {
1092
- return this._bucket.metricUploadBytes(props);
1115
+ addReplicationPolicy(policy) {
1116
+ this._bucket.addReplicationPolicy(policy);
1093
1117
  }
1094
- metricSelectReturnedBytes(props) {
1095
- return this._bucket.metricSelectReturnedBytes(props);
1118
+ get bucketRef() {
1119
+ return {
1120
+ bucketArn: this._bucket.bucketArn,
1121
+ bucketName: this._bucket.bucketName,
1122
+ };
1096
1123
  }
1097
1124
  // Override applyRemovalPolicy to apply to all resources
1098
1125
  applyRemovalPolicy(policy) {
@@ -1246,6 +1273,164 @@ class JaypieDatadogSecret extends JaypieEnvSecret {
1246
1273
  }
1247
1274
  }
1248
1275
 
1276
+ class JaypieDnsRecord extends constructs.Construct {
1277
+ constructor(scope, id, props) {
1278
+ super(scope, id);
1279
+ const { comment, recordName, type, values } = props;
1280
+ const ttl = props.ttl || cdk__namespace.Duration.seconds(cdk.CDK.DNS.CONFIG.TTL);
1281
+ // Resolve the hosted zone (supports both string and IHostedZone)
1282
+ const zone = resolveHostedZone(scope, {
1283
+ name: `${id}HostedZone`,
1284
+ zone: props.zone,
1285
+ });
1286
+ // Common properties for all record types
1287
+ const baseProps = {
1288
+ comment,
1289
+ recordName,
1290
+ ttl,
1291
+ zone,
1292
+ };
1293
+ // Create the appropriate record based on type
1294
+ switch (type) {
1295
+ case cdk.CDK.DNS.RECORD.A: {
1296
+ if (!Array.isArray(values) || values.length === 0) {
1297
+ throw new cdk.ConfigurationError("A record requires at least one IP address");
1298
+ }
1299
+ this.record = new route53.ARecord(this, "Record", {
1300
+ ...baseProps,
1301
+ target: route53.RecordTarget.fromIpAddresses(...values),
1302
+ });
1303
+ break;
1304
+ }
1305
+ case cdk.CDK.DNS.RECORD.CNAME: {
1306
+ if (!Array.isArray(values) || values.length === 0) {
1307
+ throw new cdk.ConfigurationError("CNAME record requires a domain name");
1308
+ }
1309
+ this.record = new route53.CnameRecord(this, "Record", {
1310
+ ...baseProps,
1311
+ domainName: values[0],
1312
+ });
1313
+ break;
1314
+ }
1315
+ case cdk.CDK.DNS.RECORD.MX: {
1316
+ if (!Array.isArray(values) || values.length === 0) {
1317
+ throw new cdk.ConfigurationError("MX record requires at least one mail server");
1318
+ }
1319
+ this.record = new route53.MxRecord(this, "Record", {
1320
+ ...baseProps,
1321
+ values: values,
1322
+ });
1323
+ break;
1324
+ }
1325
+ case cdk.CDK.DNS.RECORD.NS: {
1326
+ if (!Array.isArray(values) || values.length === 0) {
1327
+ throw new cdk.ConfigurationError("NS record requires at least one name server");
1328
+ }
1329
+ this.record = new route53.NsRecord(this, "Record", {
1330
+ ...baseProps,
1331
+ values: values,
1332
+ });
1333
+ break;
1334
+ }
1335
+ case cdk.CDK.DNS.RECORD.TXT: {
1336
+ if (!Array.isArray(values) || values.length === 0) {
1337
+ throw new cdk.ConfigurationError("TXT record requires at least one value");
1338
+ }
1339
+ this.record = new route53.TxtRecord(this, "Record", {
1340
+ ...baseProps,
1341
+ values: values,
1342
+ });
1343
+ break;
1344
+ }
1345
+ default:
1346
+ throw new cdk.ConfigurationError(`Unsupported DNS record type: ${type}. Supported types: A, CNAME, MX, NS, TXT`);
1347
+ }
1348
+ // Add standard tags to the DNS record
1349
+ cdk__namespace.Tags.of(this.record).add(cdk.CDK.TAG.SERVICE, cdk.CDK.SERVICE.INFRASTRUCTURE);
1350
+ cdk__namespace.Tags.of(this.record).add(cdk.CDK.TAG.ROLE, cdk.CDK.ROLE.NETWORKING);
1351
+ }
1352
+ }
1353
+
1354
+ class JaypieGitHubDeployRole extends constructs.Construct {
1355
+ constructor(scope, id, props) {
1356
+ super(scope, id);
1357
+ const { accountId, oidcProviderArn = cdk$1.Fn.importValue(cdk.CDK.IMPORT.OIDC_PROVIDER), output = true, repoRestriction: propsRepoRestriction, } = props;
1358
+ // Resolve repoRestriction from props or environment variables
1359
+ let repoRestriction = propsRepoRestriction;
1360
+ if (!repoRestriction) {
1361
+ const envRepo = process.env.CDK_ENV_REPO || process.env.PROJECT_REPO;
1362
+ if (!envRepo) {
1363
+ throw new cdk.ConfigurationError("No repoRestriction provided. Set repoRestriction prop, CDK_ENV_REPO, or PROJECT_REPO environment variable");
1364
+ }
1365
+ // Extract organization from owner/repo format and create org-wide restriction
1366
+ const organization = envRepo.split("/")[0];
1367
+ repoRestriction = `repo:${organization}/*:*`;
1368
+ }
1369
+ // Create the IAM role
1370
+ this._role = new awsIam.Role(this, "GitHubActionsRole", {
1371
+ assumedBy: new awsIam.FederatedPrincipal(oidcProviderArn, {
1372
+ StringLike: {
1373
+ "token.actions.githubusercontent.com:sub": repoRestriction,
1374
+ },
1375
+ }, "sts:AssumeRoleWithWebIdentity"),
1376
+ maxSessionDuration: cdk$1.Duration.hours(1),
1377
+ path: "/",
1378
+ });
1379
+ cdk$1.Tags.of(this._role).add(cdk.CDK.TAG.ROLE, cdk.CDK.ROLE.DEPLOY);
1380
+ // Allow the role to access the GitHub OIDC provider
1381
+ this._role.addToPolicy(new awsIam.PolicyStatement({
1382
+ actions: ["sts:AssumeRoleWithWebIdentity"],
1383
+ resources: [`arn:aws:iam::${accountId}:oidc-provider/*`],
1384
+ }));
1385
+ // Allow the role to deploy CDK apps
1386
+ this._role.addToPolicy(new awsIam.PolicyStatement({
1387
+ actions: [
1388
+ "cloudformation:CreateStack",
1389
+ "cloudformation:DeleteStack",
1390
+ "cloudformation:DescribeStackEvents",
1391
+ "cloudformation:DescribeStackResource",
1392
+ "cloudformation:DescribeStackResources",
1393
+ "cloudformation:DescribeStacks",
1394
+ "cloudformation:GetTemplate",
1395
+ "cloudformation:SetStackPolicy",
1396
+ "cloudformation:UpdateStack",
1397
+ "cloudformation:ValidateTemplate",
1398
+ "iam:PassRole",
1399
+ "route53:ListHostedZones*",
1400
+ "s3:GetObject",
1401
+ "s3:ListBucket",
1402
+ ],
1403
+ effect: awsIam.Effect.ALLOW,
1404
+ resources: ["*"],
1405
+ }));
1406
+ this._role.addToPolicy(new awsIam.PolicyStatement({
1407
+ actions: ["iam:PassRole", "sts:AssumeRole"],
1408
+ effect: awsIam.Effect.ALLOW,
1409
+ resources: [
1410
+ "arn:aws:iam::*:role/cdk-hnb659fds-deploy-role-*",
1411
+ "arn:aws:iam::*:role/cdk-hnb659fds-file-publishing-*",
1412
+ "arn:aws:iam::*:role/cdk-readOnlyRole",
1413
+ ],
1414
+ }));
1415
+ // Export the ARN of the role
1416
+ if (output !== false) {
1417
+ const outputId = typeof output === "string" ? output : "GitHubActionsRoleArn";
1418
+ new cdk$1.CfnOutput(this, outputId, {
1419
+ value: this._role.roleArn,
1420
+ });
1421
+ }
1422
+ }
1423
+ get role() {
1424
+ return this._role;
1425
+ }
1426
+ get roleArn() {
1427
+ return this._role.roleArn;
1428
+ }
1429
+ get roleName() {
1430
+ return this._role.roleName;
1431
+ }
1432
+ }
1433
+
1249
1434
  class JaypieExpressLambda extends JaypieLambda {
1250
1435
  constructor(scope, id, props) {
1251
1436
  super(scope, id, {
@@ -1261,11 +1446,12 @@ const SERVICE = {
1261
1446
  };
1262
1447
  class JaypieHostedZone extends constructs.Construct {
1263
1448
  /**
1264
- * Create a new hosted zone with query logging
1449
+ * Create a new hosted zone with query logging and optional DNS records
1265
1450
  */
1266
1451
  constructor(scope, id, props) {
1267
1452
  super(scope, id);
1268
- const { destination, zoneName, project } = props;
1453
+ const { zoneName, project } = props;
1454
+ const destination = props.destination ?? true;
1269
1455
  const service = props.service || cdk.CDK.SERVICE.INFRASTRUCTURE;
1270
1456
  // Create the log group
1271
1457
  this.logGroup = new awsLogs.LogGroup(this, "LogGroup", {
@@ -1282,10 +1468,13 @@ class JaypieHostedZone extends constructs.Construct {
1282
1468
  }
1283
1469
  // Grant Route 53 permissions to write to the log group
1284
1470
  this.logGroup.grantWrite(new awsIam.ServicePrincipal(SERVICE.ROUTE53));
1285
- // Add destination if provided
1286
- if (destination) {
1471
+ // Add destination based on configuration
1472
+ if (destination !== false) {
1473
+ const lambdaDestination = destination === true
1474
+ ? resolveDatadogLoggingDestination(scope)
1475
+ : destination;
1287
1476
  this.logGroup.addSubscriptionFilter("DatadogLambdaDestination", {
1288
- destination,
1477
+ destination: lambdaDestination,
1289
1478
  filterPattern: awsLogs.FilterPattern.allEvents(),
1290
1479
  });
1291
1480
  }
@@ -1300,6 +1489,21 @@ class JaypieHostedZone extends constructs.Construct {
1300
1489
  if (project) {
1301
1490
  cdk__namespace.Tags.of(this.hostedZone).add(cdk.CDK.TAG.PROJECT, project);
1302
1491
  }
1492
+ // Create DNS records if provided
1493
+ this.dnsRecords = [];
1494
+ if (props.records) {
1495
+ props.records.forEach((recordConfig, index) => {
1496
+ const { id, ...recordProps } = recordConfig;
1497
+ // Generate a default ID if not provided
1498
+ const recordId = id ||
1499
+ `${recordProps.type}${recordProps.recordName ? `-${recordProps.recordName}` : ""}-${index}`;
1500
+ const dnsRecord = new JaypieDnsRecord(this, recordId, {
1501
+ ...recordProps,
1502
+ zone: this.hostedZone,
1503
+ });
1504
+ this.dnsRecords.push(dnsRecord);
1505
+ });
1506
+ }
1303
1507
  }
1304
1508
  }
1305
1509
 
@@ -1348,276 +1552,348 @@ class JaypieOpenAiSecret extends JaypieEnvSecret {
1348
1552
  }
1349
1553
 
1350
1554
  /**
1351
- * Permission set types with corresponding AWS managed policies
1352
- */
1353
- exports.PermissionSetType = void 0;
1354
- (function (PermissionSetType) {
1355
- PermissionSetType["ADMINISTRATOR"] = "Administrator";
1356
- PermissionSetType["ANALYST"] = "Analyst";
1357
- PermissionSetType["DEVELOPER"] = "Developer";
1358
- })(exports.PermissionSetType || (exports.PermissionSetType = {}));
1359
- /**
1360
- * Construct to simplify AWS SSO group management.
1361
- * This construct encapsulates the complexity of creating permission sets
1362
- * and assigning them to groups across multiple AWS accounts.
1555
+ * JaypieSsoPermissions Construct
1556
+ *
1557
+ * Creates and manages AWS IAM Identity Center (SSO) permission sets and assignments
1558
+ *
1559
+ * @example
1560
+ * const permissionSets = new JaypieSsoPermissions(this, "PermissionSets", {
1561
+ * iamIdentityCenterArn: "arn:aws:sso:::instance/...",
1562
+ * administratorGroupId: "b4c8b438-4031-7000-782d-5046945fb956",
1563
+ * analystGroupId: "2488f4e8-d061-708e-abe1-c315f0e30005",
1564
+ * developerGroupId: "b438a4f8-e0e1-707c-c6e8-21841daf9ad1",
1565
+ * administratorAccountAssignments: {
1566
+ * "211125635435": ["Administrator", "Analyst", "Developer"],
1567
+ * "381492033431": ["Administrator", "Analyst"],
1568
+ * },
1569
+ * analystAccountAssignments: {
1570
+ * "211125635435": ["Analyst", "Developer"],
1571
+ * "381492033431": [],
1572
+ * },
1573
+ * developerAccountAssignments: {
1574
+ * "211125635435": ["Analyst", "Developer"],
1575
+ * "381492033431": [],
1576
+ * },
1577
+ * });
1363
1578
  */
1364
- class JaypieSsoGroups extends constructs.Construct {
1579
+ class JaypieSsoPermissions extends constructs.Construct {
1365
1580
  constructor(scope, id, props) {
1366
1581
  super(scope, id);
1367
- this.permissionSets = {};
1368
- this.instanceArn = props.instanceArn;
1369
- this.props = props;
1370
- // Create the permission sets
1371
- this.createAdministratorPermissionSet();
1372
- this.createAnalystPermissionSet();
1373
- this.createDeveloperPermissionSet();
1374
- // Create the assignments
1375
- this.createPermissionSetAssignments(props);
1376
- }
1377
- /**
1378
- * Creates the Administrator permission set with AdministratorAccess policy
1379
- * and billing access
1380
- */
1381
- createAdministratorPermissionSet() {
1382
- const defaultInlinePolicy = {
1383
- Version: "2012-10-17",
1384
- Statement: [
1582
+ const { iamIdentityCenterArn, administratorGroupId, analystGroupId, developerGroupId, administratorAccountAssignments, analystAccountAssignments, developerAccountAssignments, } = props;
1583
+ if (!iamIdentityCenterArn) {
1584
+ // If no IAM Identity Center ARN provided, skip SSO setup
1585
+ return;
1586
+ }
1587
+ //
1588
+ // Permission Sets
1589
+ //
1590
+ this.administratorPermissionSet = new awsSso.CfnPermissionSet(this, "AdministratorPermissionSet", {
1591
+ // Required
1592
+ instanceArn: iamIdentityCenterArn,
1593
+ name: "Administrator",
1594
+ // Optional
1595
+ description: "Unrestricted access",
1596
+ inlinePolicy: {
1597
+ Version: "2012-10-17",
1598
+ Statement: [
1599
+ {
1600
+ Effect: "Allow",
1601
+ Action: [
1602
+ "aws-portal:ViewUsage",
1603
+ "aws-portal:ViewBilling",
1604
+ "budgets:*",
1605
+ "cur:DescribeReportDefinitions",
1606
+ "cur:PutReportDefinition",
1607
+ "cur:DeleteReportDefinition",
1608
+ "cur:ModifyReportDefinition",
1609
+ ],
1610
+ Resource: "*",
1611
+ },
1612
+ ],
1613
+ },
1614
+ managedPolicies: [
1615
+ awsIam.ManagedPolicy.fromAwsManagedPolicyName("AdministratorAccess")
1616
+ .managedPolicyArn,
1617
+ awsIam.ManagedPolicy.fromAwsManagedPolicyName("AWSManagementConsoleBasicUserAccess").managedPolicyArn,
1618
+ ],
1619
+ sessionDuration: cdk$1.Duration.hours(1).toIsoString(),
1620
+ tags: [
1385
1621
  {
1386
- Effect: "Allow",
1387
- Action: [
1388
- "aws-portal:*",
1389
- "budgets:*",
1390
- "ce:*",
1391
- "cost-optimization-hub:*",
1392
- ],
1393
- Resource: "*",
1622
+ key: cdk.CDK.TAG.SERVICE,
1623
+ value: cdk.CDK.SERVICE.SSO,
1394
1624
  },
1395
- ],
1396
- };
1397
- // Merge with any additional policy statements provided for administrators
1398
- const mergedPolicy = this.mergeInlinePolicies(defaultInlinePolicy, this.props?.inlinePolicyStatements?.administrators);
1399
- const permissionSet = new sso__namespace.CfnPermissionSet(this, "AdministratorPermissionSet", {
1400
- instanceArn: this.instanceArn,
1401
- name: exports.PermissionSetType.ADMINISTRATOR,
1402
- description: "Full administrative access to all AWS services and resources",
1403
- sessionDuration: cdk$1.Duration.hours(8).toIsoString(),
1404
- managedPolicies: ["arn:aws:iam::aws:policy/AdministratorAccess"],
1405
- inlinePolicy: mergedPolicy,
1406
- });
1407
- cdk$1.Tags.of(permissionSet).add(cdk.CDK.TAG.SERVICE, cdk.CDK.SERVICE.SSO);
1408
- this.permissionSets[exports.PermissionSetType.ADMINISTRATOR] = permissionSet;
1409
- }
1410
- /**
1411
- * Creates the Analyst permission set with ReadOnlyAccess policy
1412
- * and limited write access
1413
- */
1414
- createAnalystPermissionSet() {
1415
- const defaultInlinePolicy = {
1416
- Version: "2012-10-17",
1417
- Statement: [
1418
1625
  {
1419
- Effect: "Allow",
1420
- Action: [
1421
- "aws-portal:ViewBilling",
1422
- "aws-portal:ViewAccount",
1423
- "budgets:ViewBudget",
1424
- "cloudwatch:PutDashboard",
1425
- "cloudwatch:PutMetricData",
1426
- "s3:PutObject",
1427
- "s3:GetObject",
1428
- "s3:ListBucket",
1429
- ],
1430
- Resource: "*",
1626
+ key: cdk.CDK.TAG.ROLE,
1627
+ value: cdk.CDK.ROLE.SECURITY,
1431
1628
  },
1432
1629
  ],
1433
- };
1434
- // Merge with any additional policy statements provided for analysts
1435
- const mergedPolicy = this.mergeInlinePolicies(defaultInlinePolicy, this.props?.inlinePolicyStatements?.analysts);
1436
- const permissionSet = new sso__namespace.CfnPermissionSet(this, "AnalystPermissionSet", {
1437
- instanceArn: this.instanceArn,
1438
- name: exports.PermissionSetType.ANALYST,
1439
- description: "Read-only access with billing visibility and limited write access",
1440
- sessionDuration: cdk$1.Duration.hours(4).toIsoString(),
1441
- managedPolicies: ["arn:aws:iam::aws:policy/ReadOnlyAccess"],
1442
- inlinePolicy: mergedPolicy,
1443
1630
  });
1444
- cdk$1.Tags.of(permissionSet).add(cdk.CDK.TAG.SERVICE, cdk.CDK.SERVICE.SSO);
1445
- this.permissionSets[exports.PermissionSetType.ANALYST] = permissionSet;
1446
- }
1447
- /**
1448
- * Creates the Developer permission set with SystemAdministrator policy
1449
- * and expanded write access
1450
- */
1451
- createDeveloperPermissionSet() {
1452
- const defaultInlinePolicy = {
1453
- Version: "2012-10-17",
1454
- Statement: [
1631
+ this.analystPermissionSet = new awsSso.CfnPermissionSet(this, "AnalystPermissionSet", {
1632
+ // Required
1633
+ instanceArn: iamIdentityCenterArn,
1634
+ name: "Analyst",
1635
+ // Optional
1636
+ description: "Read-only access; may expand to limited write access",
1637
+ inlinePolicy: {
1638
+ Version: "2012-10-17",
1639
+ Statement: [
1640
+ {
1641
+ Effect: "Allow",
1642
+ Action: [
1643
+ "aws-portal:ViewUsage",
1644
+ "aws-portal:ViewBilling",
1645
+ "budgets:Describe*",
1646
+ "budgets:View*",
1647
+ "ce:Get*",
1648
+ "ce:List*",
1649
+ "cloudformation:Describe*",
1650
+ "cloudformation:Get*",
1651
+ "cloudformation:List*",
1652
+ "cloudwatch:BatchGet*",
1653
+ "cloudwatch:Get*",
1654
+ "cloudwatch:List*",
1655
+ "cost-optimization-hub:Get*",
1656
+ "cost-optimization-hub:List*",
1657
+ "ec2:Describe*",
1658
+ "ec2:Get*",
1659
+ "ec2:List*",
1660
+ "ec2:Search*",
1661
+ "iam:Get*",
1662
+ "iam:List*",
1663
+ "iam:PassRole",
1664
+ "lambda:Get*",
1665
+ "lambda:List*",
1666
+ "logs:Describe*",
1667
+ "logs:Get*",
1668
+ "logs:List*",
1669
+ "pipes:Describe*",
1670
+ "pipes:List*",
1671
+ "s3:Get*",
1672
+ "s3:List*",
1673
+ "secretsmanager:GetRandomPassword",
1674
+ "secretsmanager:GetResourcePolicy",
1675
+ "secretsmanager:List*",
1676
+ "securityhub:Describe*",
1677
+ "securityhub:Get*",
1678
+ "securityhub:List*",
1679
+ "servicecatalog:Describe*",
1680
+ "sns:Get*",
1681
+ "sns:List*",
1682
+ "sqs:Get*",
1683
+ "sqs:List*",
1684
+ "states:Describe*",
1685
+ "states:Get*",
1686
+ "states:List*",
1687
+ "tag:*",
1688
+ "xray:*",
1689
+ ],
1690
+ Resource: "*",
1691
+ },
1692
+ ],
1693
+ },
1694
+ managedPolicies: [
1695
+ awsIam.ManagedPolicy.fromAwsManagedPolicyName("AmazonQDeveloperAccess")
1696
+ .managedPolicyArn,
1697
+ awsIam.ManagedPolicy.fromAwsManagedPolicyName("AWSManagementConsoleBasicUserAccess").managedPolicyArn,
1698
+ awsIam.ManagedPolicy.fromAwsManagedPolicyName("ReadOnlyAccess")
1699
+ .managedPolicyArn,
1700
+ ],
1701
+ sessionDuration: cdk$1.Duration.hours(12).toIsoString(),
1702
+ tags: [
1455
1703
  {
1456
- Effect: "Allow",
1457
- Action: [
1458
- "cloudwatch:*",
1459
- "logs:*",
1460
- "lambda:*",
1461
- "apigateway:*",
1462
- "dynamodb:*",
1463
- "s3:*",
1464
- "sns:*",
1465
- "sqs:*",
1466
- "events:*",
1467
- "ecr:*",
1468
- "ecs:*",
1469
- "codebuild:*",
1470
- ],
1471
- Resource: "*",
1704
+ key: cdk.CDK.TAG.SERVICE,
1705
+ value: cdk.CDK.SERVICE.SSO,
1472
1706
  },
1473
1707
  {
1474
- Effect: "Deny",
1475
- Action: [
1476
- "iam:*User*",
1477
- "iam:*Role*",
1478
- "iam:*Policy*",
1479
- "organizations:*",
1480
- "account:*",
1481
- ],
1482
- Resource: "*",
1708
+ key: cdk.CDK.TAG.ROLE,
1709
+ value: cdk.CDK.ROLE.SECURITY,
1483
1710
  },
1484
1711
  ],
1485
- };
1486
- // Merge with any additional policy statements provided for developers
1487
- const mergedPolicy = this.mergeInlinePolicies(defaultInlinePolicy, this.props?.inlinePolicyStatements?.developers);
1488
- const permissionSet = new sso__namespace.CfnPermissionSet(this, "DeveloperPermissionSet", {
1489
- instanceArn: this.instanceArn,
1490
- name: exports.PermissionSetType.DEVELOPER,
1491
- description: "System administrator access with expanded write permissions",
1492
- sessionDuration: cdk$1.Duration.hours(8).toIsoString(),
1712
+ });
1713
+ this.developerPermissionSet = new awsSso.CfnPermissionSet(this, "DeveloperPermissionSet", {
1714
+ // Required
1715
+ instanceArn: iamIdentityCenterArn,
1716
+ name: "Developer",
1717
+ // Optional
1718
+ description: "Administrative access with limited restrictions",
1719
+ inlinePolicy: {
1720
+ Version: "2012-10-17",
1721
+ Statement: [
1722
+ {
1723
+ Effect: "Allow",
1724
+ Action: [
1725
+ "budgets:*",
1726
+ "ce:*",
1727
+ "cloudformation:*",
1728
+ "cloudwatch:*",
1729
+ "cost-optimization-hub:*",
1730
+ "ec2:*",
1731
+ "iam:Get*",
1732
+ "iam:List*",
1733
+ "iam:PassRole",
1734
+ "lambda:*",
1735
+ "logs:*",
1736
+ "pipes:*",
1737
+ "s3:*",
1738
+ "secretsmanager:*",
1739
+ "securityhub:*",
1740
+ "servicecatalog:*",
1741
+ "sns:*",
1742
+ "sqs:*",
1743
+ "states:*",
1744
+ "tag:*",
1745
+ "xray:*",
1746
+ ],
1747
+ Resource: "*",
1748
+ },
1749
+ ],
1750
+ },
1493
1751
  managedPolicies: [
1494
- "arn:aws:iam::aws:policy/job-function/SystemAdministrator",
1752
+ awsIam.ManagedPolicy.fromAwsManagedPolicyName("AmazonQDeveloperAccess")
1753
+ .managedPolicyArn,
1754
+ awsIam.ManagedPolicy.fromAwsManagedPolicyName("AWSManagementConsoleBasicUserAccess").managedPolicyArn,
1755
+ awsIam.ManagedPolicy.fromAwsManagedPolicyName("ReadOnlyAccess")
1756
+ .managedPolicyArn,
1757
+ awsIam.ManagedPolicy.fromAwsManagedPolicyName("job-function/SystemAdministrator").managedPolicyArn,
1758
+ ],
1759
+ sessionDuration: cdk$1.Duration.hours(4).toIsoString(),
1760
+ tags: [
1761
+ {
1762
+ key: cdk.CDK.TAG.SERVICE,
1763
+ value: cdk.CDK.SERVICE.SSO,
1764
+ },
1765
+ {
1766
+ key: cdk.CDK.TAG.ROLE,
1767
+ value: cdk.CDK.ROLE.SECURITY,
1768
+ },
1495
1769
  ],
1496
- inlinePolicy: mergedPolicy,
1497
1770
  });
1498
- cdk$1.Tags.of(permissionSet).add(cdk.CDK.TAG.SERVICE, cdk.CDK.SERVICE.SSO);
1499
- this.permissionSets[exports.PermissionSetType.DEVELOPER] = permissionSet;
1500
- }
1501
- /**
1502
- * Gets the permission set for the specified type
1503
- */
1504
- getPermissionSet(type) {
1505
- return this.permissionSets[type];
1771
+ // Map permission set names to their ARNs and labels
1772
+ const permissionSetMap = {
1773
+ Administrator: {
1774
+ arn: this.administratorPermissionSet.attrPermissionSetArn,
1775
+ label: "Administrator",
1776
+ },
1777
+ Analyst: {
1778
+ arn: this.analystPermissionSet.attrPermissionSetArn,
1779
+ label: "Analyst",
1780
+ },
1781
+ Developer: {
1782
+ arn: this.developerPermissionSet.attrPermissionSetArn,
1783
+ label: "Developer",
1784
+ },
1785
+ };
1786
+ //
1787
+ // Assignments
1788
+ //
1789
+ // Helper function to create assignments for a group
1790
+ const createAssignments = (groupId, accountAssignments) => {
1791
+ if (!groupId || !accountAssignments) {
1792
+ return; // Skip if group ID or assignments not provided
1793
+ }
1794
+ Object.keys(accountAssignments).forEach((accountId) => {
1795
+ const permissionSetNames = accountAssignments[accountId];
1796
+ permissionSetNames.forEach((permissionSetName) => {
1797
+ const permissionSet = permissionSetMap[permissionSetName];
1798
+ if (!permissionSet) {
1799
+ throw new cdk.ConfigurationError(`Unknown permission set: ${permissionSetName}. Valid options: ${Object.keys(permissionSetMap).join(", ")}`);
1800
+ }
1801
+ const accountAssignment = new awsSso.CfnAssignment(this, `AccountAssignment-${accountId}-${permissionSet.label}Role-${groupId}Group`, {
1802
+ // Required
1803
+ instanceArn: iamIdentityCenterArn,
1804
+ permissionSetArn: permissionSet.arn,
1805
+ principalId: groupId,
1806
+ principalType: cdk.CDK.PRINCIPAL_TYPE.GROUP,
1807
+ targetId: accountId,
1808
+ targetType: cdk.CDK.TARGET_TYPE.AWS_ACCOUNT,
1809
+ });
1810
+ cdk$1.Tags.of(accountAssignment).add(cdk.CDK.TAG.SERVICE, cdk.CDK.SERVICE.SSO);
1811
+ cdk$1.Tags.of(accountAssignment).add(cdk.CDK.TAG.ROLE, cdk.CDK.ROLE.SECURITY);
1812
+ });
1813
+ });
1814
+ };
1815
+ // Create assignments for each group
1816
+ createAssignments(administratorGroupId, administratorAccountAssignments);
1817
+ createAssignments(analystGroupId, analystAccountAssignments);
1818
+ createAssignments(developerGroupId, developerAccountAssignments);
1506
1819
  }
1507
- /**
1508
- * Merges default inline policies with additional user-provided policy statements
1509
- *
1510
- * @param defaultPolicy - The default policy object with Version and Statement properties
1511
- * @param additionalStatements - Optional additional policy statements to merge
1512
- * @returns The merged policy object
1513
- */
1514
- mergeInlinePolicies(defaultPolicy, additionalStatements) {
1515
- if (!additionalStatements || additionalStatements.length === 0) {
1516
- return defaultPolicy;
1820
+ }
1821
+
1822
+ //
1823
+ //
1824
+ // Constants
1825
+ //
1826
+ const DEFAULT_APPLICATION_ID = "arn:aws:serverlessrepo:us-east-2:004480582608:applications/SSOSync";
1827
+ const DEFAULT_APPLICATION_VERSION = "2.3.3";
1828
+ const DEFAULT_GOOGLE_GROUP_MATCH = "name:AWS*";
1829
+ //
1830
+ //
1831
+ // Class
1832
+ //
1833
+ class JaypieSsoSyncApplication extends constructs.Construct {
1834
+ constructor(scope, id = "SSOSyncApplication", props = {}) {
1835
+ super(scope, id);
1836
+ const { googleAdminEmail, googleAdminEmailEnvKey = "CDK_ENV_SSOSYNC_GOOGLE_ADMIN_EMAIL", googleCredentials, googleCredentialsEnvKey = "CDK_ENV_SSOSYNC_GOOGLE_CREDENTIALS", googleGroupMatch, googleGroupMatchEnvKey = "CDK_ENV_SSOSYNC_GOOGLE_GROUP_MATCH", identityStoreId, identityStoreIdEnvKey = "CDK_ENV_SSOSYNC_IDENTITY_STORE_ID", scimEndpointAccessToken, scimEndpointAccessTokenEnvKey = "CDK_ENV_SCIM_ENDPOINT_ACCESS_TOKEN", scimEndpointUrl, scimEndpointUrlEnvKey = "CDK_ENV_SSOSYNC_SCIM_ENDPOINT_URL", semanticVersion, semanticVersionEnvKey = "CDK_ENV_SSOSYNC_SEMANTIC_VERSION", ssoSyncApplicationId = DEFAULT_APPLICATION_ID, tags, } = props;
1837
+ // Resolve all values from props or environment variables
1838
+ const resolvedGoogleAdminEmail = googleAdminEmail || process.env[googleAdminEmailEnvKey];
1839
+ const resolvedGoogleCredentials = googleCredentials || process.env[googleCredentialsEnvKey];
1840
+ const resolvedGoogleGroupMatch = googleGroupMatch ||
1841
+ process.env[googleGroupMatchEnvKey] ||
1842
+ DEFAULT_GOOGLE_GROUP_MATCH;
1843
+ const resolvedIdentityStoreId = identityStoreId || process.env[identityStoreIdEnvKey];
1844
+ const resolvedScimEndpointAccessToken = scimEndpointAccessToken || process.env[scimEndpointAccessTokenEnvKey];
1845
+ const resolvedScimEndpointUrl = scimEndpointUrl || process.env[scimEndpointUrlEnvKey];
1846
+ const resolvedSemanticVersion = semanticVersion ||
1847
+ process.env[semanticVersionEnvKey] ||
1848
+ DEFAULT_APPLICATION_VERSION;
1849
+ // Validate required parameters
1850
+ const missingParams = [];
1851
+ if (!resolvedGoogleAdminEmail) {
1852
+ missingParams.push(`googleAdminEmail or ${googleAdminEmailEnvKey} environment variable`);
1517
1853
  }
1518
- // Create a deep copy of the default policy to avoid modifying the original
1519
- const mergedPolicy = JSON.parse(JSON.stringify(defaultPolicy));
1520
- // Add the additional statements to the existing statements
1521
- mergedPolicy.Statement = [
1522
- ...mergedPolicy.Statement,
1523
- ...additionalStatements,
1524
- ];
1525
- return mergedPolicy;
1526
- }
1527
- /**
1528
- * Creates assignments between permission sets, groups, and accounts
1529
- * based on the provided configuration
1530
- */
1531
- createPermissionSetAssignments(props) {
1532
- // Administrator assignments
1533
- this.assignAdministratorPermissions(props);
1534
- // Analyst assignments
1535
- this.assignAnalystPermissions(props);
1536
- // Developer assignments
1537
- this.assignDeveloperPermissions(props);
1538
- }
1539
- /**
1540
- * Assigns Administrator permissions to appropriate accounts
1541
- */
1542
- assignAdministratorPermissions(props) {
1543
- const administratorGroup = props.groupMap.administrators;
1544
- const administratorPermissionSet = this.permissionSets[exports.PermissionSetType.ADMINISTRATOR];
1545
- // Administrators get access to all accounts
1546
- const allAccounts = [
1547
- ...props.accountMap.development,
1548
- ...props.accountMap.management,
1549
- ...props.accountMap.operations,
1550
- ...props.accountMap.production,
1551
- ...props.accountMap.sandbox,
1552
- ...props.accountMap.security,
1553
- ...props.accountMap.stage,
1554
- ];
1555
- // Create assignments for each account
1556
- allAccounts.forEach((accountId, index) => {
1557
- const assignment = new sso__namespace.CfnAssignment(this, `AdministratorAssignment${index}`, {
1558
- instanceArn: this.instanceArn,
1559
- permissionSetArn: administratorPermissionSet.attrPermissionSetArn,
1560
- principalId: administratorGroup,
1561
- principalType: "GROUP",
1562
- targetId: accountId,
1563
- targetType: "AWS_ACCOUNT",
1564
- });
1565
- cdk$1.Tags.of(assignment).add(cdk.CDK.TAG.SERVICE, cdk.CDK.SERVICE.SSO);
1566
- cdk$1.Tags.of(assignment).add("Group", "administrators");
1854
+ if (!resolvedGoogleCredentials) {
1855
+ missingParams.push(`googleCredentials or ${googleCredentialsEnvKey} environment variable`);
1856
+ }
1857
+ if (!resolvedIdentityStoreId) {
1858
+ missingParams.push(`identityStoreId or ${identityStoreIdEnvKey} environment variable`);
1859
+ }
1860
+ if (!resolvedScimEndpointAccessToken) {
1861
+ missingParams.push(`scimEndpointAccessToken or ${scimEndpointAccessTokenEnvKey} environment variable`);
1862
+ }
1863
+ if (!resolvedScimEndpointUrl) {
1864
+ missingParams.push(`scimEndpointUrl or ${scimEndpointUrlEnvKey} environment variable`);
1865
+ }
1866
+ if (missingParams.length > 0) {
1867
+ throw new errors.ConfigurationError(`JaypieSsoSyncApplication missing required configuration: ${missingParams.join(", ")}`);
1868
+ }
1869
+ // Create the SSO Sync Application
1870
+ // Type assertion is safe because we validated all required values above
1871
+ this._application = new awsSam.CfnApplication(this, "Application", {
1872
+ location: {
1873
+ applicationId: ssoSyncApplicationId,
1874
+ semanticVersion: resolvedSemanticVersion,
1875
+ },
1876
+ parameters: {
1877
+ GoogleAdminEmail: resolvedGoogleAdminEmail,
1878
+ GoogleCredentials: resolvedGoogleCredentials,
1879
+ GoogleGroupMatch: resolvedGoogleGroupMatch,
1880
+ IdentityStoreID: resolvedIdentityStoreId,
1881
+ Region: cdk$1.Stack.of(this).region,
1882
+ SCIMEndpointAccessToken: resolvedScimEndpointAccessToken,
1883
+ SCIMEndpointUrl: resolvedScimEndpointUrl,
1884
+ },
1567
1885
  });
1568
- }
1569
- /**
1570
- * Assigns Analyst permissions to appropriate accounts
1571
- */
1572
- assignAnalystPermissions(props) {
1573
- const analystGroup = props.groupMap.analysts;
1574
- const analystPermissionSet = this.permissionSets[exports.PermissionSetType.ANALYST];
1575
- // Analysts get access to development, management, sandbox, and stage accounts
1576
- const analystAccounts = [
1577
- ...props.accountMap.development,
1578
- ...props.accountMap.management,
1579
- ...props.accountMap.sandbox,
1580
- ...props.accountMap.stage,
1581
- ];
1582
- // Create assignments for each account
1583
- analystAccounts.forEach((accountId, index) => {
1584
- const assignment = new sso__namespace.CfnAssignment(this, `AnalystAssignment${index}`, {
1585
- instanceArn: this.instanceArn,
1586
- permissionSetArn: analystPermissionSet.attrPermissionSetArn,
1587
- principalId: analystGroup,
1588
- principalType: "GROUP",
1589
- targetId: accountId,
1590
- targetType: "AWS_ACCOUNT",
1591
- });
1592
- cdk$1.Tags.of(assignment).add(cdk.CDK.TAG.SERVICE, cdk.CDK.SERVICE.SSO);
1593
- cdk$1.Tags.of(assignment).add("Group", "analysts");
1886
+ // Add tags
1887
+ const defaultTags = {
1888
+ [cdk.CDK.TAG.ROLE]: cdk.CDK.ROLE.SECURITY,
1889
+ };
1890
+ const allTags = { ...defaultTags, ...tags };
1891
+ Object.entries(allTags).forEach(([key, value]) => {
1892
+ cdk$1.Tags.of(this._application).add(key, value);
1594
1893
  });
1595
1894
  }
1596
- /**
1597
- * Assigns Developer permissions to appropriate accounts
1598
- */
1599
- assignDeveloperPermissions(props) {
1600
- const developerGroup = props.groupMap.developers;
1601
- const developerPermissionSet = this.permissionSets[exports.PermissionSetType.DEVELOPER];
1602
- // Developers get access to development, sandbox, and stage accounts
1603
- const developerAccounts = [
1604
- ...props.accountMap.development,
1605
- ...props.accountMap.sandbox,
1606
- ...props.accountMap.stage,
1607
- ];
1608
- // Create assignments for each account
1609
- developerAccounts.forEach((accountId, index) => {
1610
- const assignment = new sso__namespace.CfnAssignment(this, `DeveloperAssignment${index}`, {
1611
- instanceArn: this.instanceArn,
1612
- permissionSetArn: developerPermissionSet.attrPermissionSetArn,
1613
- principalId: developerGroup,
1614
- principalType: "GROUP",
1615
- targetId: accountId,
1616
- targetType: "AWS_ACCOUNT",
1617
- });
1618
- cdk$1.Tags.of(assignment).add(cdk.CDK.TAG.SERVICE, cdk.CDK.SERVICE.SSO);
1619
- cdk$1.Tags.of(assignment).add("Group", "developers");
1620
- });
1895
+ get application() {
1896
+ return this._application;
1621
1897
  }
1622
1898
  }
1623
1899
 
@@ -1879,21 +2155,34 @@ class JaypieWebDeploymentBucket extends constructs.Construct {
1879
2155
  applyRemovalPolicy(policy) {
1880
2156
  this.bucket.applyRemovalPolicy(policy);
1881
2157
  }
2158
+ get bucketRef() {
2159
+ return {
2160
+ bucketArn: this.bucket.bucketArn,
2161
+ bucketName: this.bucket.bucketName,
2162
+ };
2163
+ }
1882
2164
  }
1883
2165
 
2166
+ Object.defineProperty(exports, "CDK", {
2167
+ enumerable: true,
2168
+ get: function () { return cdk.CDK; }
2169
+ });
1884
2170
  exports.JaypieApiGateway = JaypieApiGateway;
1885
2171
  exports.JaypieAppStack = JaypieAppStack;
1886
2172
  exports.JaypieBucketQueuedLambda = JaypieBucketQueuedLambda;
1887
2173
  exports.JaypieDatadogSecret = JaypieDatadogSecret;
2174
+ exports.JaypieDnsRecord = JaypieDnsRecord;
1888
2175
  exports.JaypieEnvSecret = JaypieEnvSecret;
1889
2176
  exports.JaypieExpressLambda = JaypieExpressLambda;
2177
+ exports.JaypieGitHubDeployRole = JaypieGitHubDeployRole;
1890
2178
  exports.JaypieHostedZone = JaypieHostedZone;
1891
2179
  exports.JaypieInfrastructureStack = JaypieInfrastructureStack;
1892
2180
  exports.JaypieLambda = JaypieLambda;
1893
2181
  exports.JaypieMongoDbSecret = JaypieMongoDbSecret;
1894
2182
  exports.JaypieOpenAiSecret = JaypieOpenAiSecret;
1895
2183
  exports.JaypieQueuedLambda = JaypieQueuedLambda;
1896
- exports.JaypieSsoGroups = JaypieSsoGroups;
2184
+ exports.JaypieSsoPermissions = JaypieSsoPermissions;
2185
+ exports.JaypieSsoSyncApplication = JaypieSsoSyncApplication;
1897
2186
  exports.JaypieStack = JaypieStack;
1898
2187
  exports.JaypieTraceSigningKeySecret = JaypieTraceSigningKeySecret;
1899
2188
  exports.JaypieWebDeploymentBucket = JaypieWebDeploymentBucket;
@@ -1906,7 +2195,9 @@ exports.isEnv = isEnv;
1906
2195
  exports.isProductionEnv = isProductionEnv;
1907
2196
  exports.isSandboxEnv = isSandboxEnv;
1908
2197
  exports.jaypieLambdaEnv = jaypieLambdaEnv;
2198
+ exports.resolveDatadogForwarderFunction = resolveDatadogForwarderFunction;
1909
2199
  exports.resolveDatadogLayers = resolveDatadogLayers;
2200
+ exports.resolveDatadogLoggingDestination = resolveDatadogLoggingDestination;
1910
2201
  exports.resolveHostedZone = resolveHostedZone;
1911
2202
  exports.resolveParamsAndSecrets = resolveParamsAndSecrets;
1912
2203
  //# sourceMappingURL=index.cjs.map