quidproquo-deploy-awscdk 0.1.7 → 0.1.8

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 (52) hide show
  1. package/lib/commonjs/constructs/feature/config/waf/wafRules.js +12 -2
  2. package/lib/commonjs/constructs/feature/config/waf/wafRules.js.map +1 -1
  3. package/lib/commonjs/constructs/feature/core/keyValueStore/QpqCoreKeyValueStoreConstruct.d.ts +1 -1
  4. package/lib/commonjs/constructs/feature/core/keyValueStore/QpqCoreKeyValueStoreConstruct.js +2 -6
  5. package/lib/commonjs/constructs/feature/core/keyValueStore/QpqCoreKeyValueStoreConstruct.js.map +1 -1
  6. package/lib/commonjs/constructs/feature/core/parameter/QpqCoreParameterConstruct.d.ts +1 -1
  7. package/lib/commonjs/constructs/feature/core/parameter/QpqCoreParameterConstruct.js +10 -12
  8. package/lib/commonjs/constructs/feature/core/parameter/QpqCoreParameterConstruct.js.map +1 -1
  9. package/lib/commonjs/constructs/feature/core/queue/QpqApiCoreQueueConstruct.js +4 -1
  10. package/lib/commonjs/constructs/feature/core/queue/QpqApiCoreQueueConstruct.js.map +1 -1
  11. package/lib/commonjs/constructs/feature/core/secret/QpqCoreSecretConstruct.d.ts +1 -1
  12. package/lib/commonjs/constructs/feature/core/secret/QpqCoreSecretConstruct.js +10 -12
  13. package/lib/commonjs/constructs/feature/core/secret/QpqCoreSecretConstruct.js.map +1 -1
  14. package/lib/commonjs/constructs/feature/core/storageDrive/QpqCoreStorageDriveConstruct.d.ts +1 -1
  15. package/lib/commonjs/constructs/feature/core/storageDrive/QpqCoreStorageDriveConstruct.js +4 -6
  16. package/lib/commonjs/constructs/feature/core/storageDrive/QpqCoreStorageDriveConstruct.js.map +1 -1
  17. package/lib/commonjs/stacks/InfQpqServiceStack.js +4 -4
  18. package/lib/commonjs/stacks/InfQpqServiceStack.js.map +1 -1
  19. package/lib/commonjs/utils/qpqDeployAwsCdkUtils.d.ts +1 -0
  20. package/lib/commonjs/utils/qpqDeployAwsCdkUtils.js +30 -1
  21. package/lib/commonjs/utils/qpqDeployAwsCdkUtils.js.map +1 -1
  22. package/lib/esm/constructs/feature/config/waf/wafRules.js +13 -3
  23. package/lib/esm/constructs/feature/config/waf/wafRules.js.map +1 -1
  24. package/lib/esm/constructs/feature/core/keyValueStore/QpqCoreKeyValueStoreConstruct.d.ts +1 -1
  25. package/lib/esm/constructs/feature/core/keyValueStore/QpqCoreKeyValueStoreConstruct.js +2 -6
  26. package/lib/esm/constructs/feature/core/keyValueStore/QpqCoreKeyValueStoreConstruct.js.map +1 -1
  27. package/lib/esm/constructs/feature/core/parameter/QpqCoreParameterConstruct.d.ts +1 -1
  28. package/lib/esm/constructs/feature/core/parameter/QpqCoreParameterConstruct.js +11 -13
  29. package/lib/esm/constructs/feature/core/parameter/QpqCoreParameterConstruct.js.map +1 -1
  30. package/lib/esm/constructs/feature/core/queue/QpqApiCoreQueueConstruct.js +4 -1
  31. package/lib/esm/constructs/feature/core/queue/QpqApiCoreQueueConstruct.js.map +1 -1
  32. package/lib/esm/constructs/feature/core/secret/QpqCoreSecretConstruct.d.ts +1 -1
  33. package/lib/esm/constructs/feature/core/secret/QpqCoreSecretConstruct.js +11 -13
  34. package/lib/esm/constructs/feature/core/secret/QpqCoreSecretConstruct.js.map +1 -1
  35. package/lib/esm/constructs/feature/core/storageDrive/QpqCoreStorageDriveConstruct.d.ts +1 -1
  36. package/lib/esm/constructs/feature/core/storageDrive/QpqCoreStorageDriveConstruct.js +4 -6
  37. package/lib/esm/constructs/feature/core/storageDrive/QpqCoreStorageDriveConstruct.js.map +1 -1
  38. package/lib/esm/stacks/InfQpqServiceStack.js +4 -4
  39. package/lib/esm/stacks/InfQpqServiceStack.js.map +1 -1
  40. package/lib/esm/utils/qpqDeployAwsCdkUtils.d.ts +1 -0
  41. package/lib/esm/utils/qpqDeployAwsCdkUtils.js +28 -0
  42. package/lib/esm/utils/qpqDeployAwsCdkUtils.js.map +1 -1
  43. package/package.json +7 -7
  44. package/src/constructs/feature/config/waf/wafRules.test.ts +49 -0
  45. package/src/constructs/feature/config/waf/wafRules.ts +25 -3
  46. package/src/constructs/feature/core/keyValueStore/QpqCoreKeyValueStoreConstruct.ts +7 -7
  47. package/src/constructs/feature/core/parameter/QpqCoreParameterConstruct.ts +19 -16
  48. package/src/constructs/feature/core/queue/QpqApiCoreQueueConstruct.ts +4 -1
  49. package/src/constructs/feature/core/secret/QpqCoreSecretConstruct.ts +19 -16
  50. package/src/constructs/feature/core/storageDrive/QpqCoreStorageDriveConstruct.ts +9 -7
  51. package/src/stacks/InfQpqServiceStack.ts +4 -4
  52. package/src/utils/qpqDeployAwsCdkUtils.ts +37 -0
@@ -9,8 +9,17 @@ const managedRuleGroupVendorNames = {
9
9
  [quidproquo_config_aws_1.WafManagedRuleGroup.ipReputation]: 'AWSManagedRulesAmazonIpReputationList',
10
10
  };
11
11
  const defaultManagedRuleGroups = [quidproquo_config_aws_1.WafManagedRuleGroup.common, quidproquo_config_aws_1.WafManagedRuleGroup.knownBadInputs, quidproquo_config_aws_1.WafManagedRuleGroup.sqli];
12
- const buildManagedRuleGroupRule = (ruleGroup, priority) => {
12
+ const overrideActionsToUse = {
13
+ [quidproquo_config_aws_1.WafRuleOverrideAction.count]: { count: {} },
14
+ };
15
+ const buildManagedRuleGroupRule = (ruleGroup, priority, overrides) => {
13
16
  const vendorName = managedRuleGroupVendorNames[ruleGroup];
17
+ const ruleActionOverrides = (overrides === null || overrides === void 0 ? void 0 : overrides.length)
18
+ ? overrides.map((override) => ({
19
+ name: override.name,
20
+ actionToUse: overrideActionsToUse[override.action],
21
+ }))
22
+ : undefined;
14
23
  return {
15
24
  name: vendorName,
16
25
  priority,
@@ -19,6 +28,7 @@ const buildManagedRuleGroupRule = (ruleGroup, priority) => {
19
28
  managedRuleGroupStatement: {
20
29
  vendorName: 'AWS',
21
30
  name: vendorName,
31
+ ruleActionOverrides,
22
32
  },
23
33
  },
24
34
  visibilityConfig: {
@@ -58,7 +68,7 @@ const buildRateLimitRule = (rateLimit, priority) => ({
58
68
  // Rate limits run first (cheap counters), then the managed rule groups.
59
69
  const buildWebAclRules = (wafConfig) => {
60
70
  const rateLimitRules = (wafConfig.rateLimits || []).map((rateLimit, index) => buildRateLimitRule(rateLimit, index));
61
- const managedRules = (wafConfig.managedRuleGroups || defaultManagedRuleGroups).map((ruleGroup, index) => buildManagedRuleGroupRule(ruleGroup, rateLimitRules.length + index));
71
+ const managedRules = (wafConfig.managedRuleGroups || defaultManagedRuleGroups).map((ruleGroup, index) => { var _a; return buildManagedRuleGroupRule(ruleGroup, rateLimitRules.length + index, (_a = wafConfig.managedRuleOverrides) === null || _a === void 0 ? void 0 : _a[ruleGroup]); });
62
72
  return [...rateLimitRules, ...managedRules];
63
73
  };
64
74
  exports.buildWebAclRules = buildWebAclRules;
@@ -1 +1 @@
1
- {"version":3,"file":"wafRules.js","sourceRoot":"","sources":["../../../../../../src/constructs/feature/config/waf/wafRules.ts"],"names":[],"mappings":";;;AAAA,iEAAwG;AAIxG,MAAM,2BAA2B,GAAwC;IACvE,CAAC,2CAAmB,CAAC,MAAM,CAAC,EAAE,8BAA8B;IAC5D,CAAC,2CAAmB,CAAC,cAAc,CAAC,EAAE,sCAAsC;IAC5E,CAAC,2CAAmB,CAAC,IAAI,CAAC,EAAE,4BAA4B;IACxD,CAAC,2CAAmB,CAAC,YAAY,CAAC,EAAE,uCAAuC;CAC5E,CAAC;AAEF,MAAM,wBAAwB,GAA0B,CAAC,2CAAmB,CAAC,MAAM,EAAE,2CAAmB,CAAC,cAAc,EAAE,2CAAmB,CAAC,IAAI,CAAC,CAAC;AAEnJ,MAAM,yBAAyB,GAAG,CAAC,SAA8B,EAAE,QAAgB,EAAoC,EAAE;IACvH,MAAM,UAAU,GAAG,2BAA2B,CAAC,SAAS,CAAC,CAAC;IAE1D,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,QAAQ;QACR,cAAc,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QAC5B,SAAS,EAAE;YACT,yBAAyB,EAAE;gBACzB,UAAU,EAAE,KAAK;gBACjB,IAAI,EAAE,UAAU;aACjB;SACF;QACD,gBAAgB,EAAE;YAChB,wBAAwB,EAAE,IAAI;YAC9B,UAAU,EAAE,UAAU;YACtB,sBAAsB,EAAE,IAAI;SAC7B;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,kBAAkB,GAAG,CAAC,SAAuB,EAAE,QAAgB,EAAoC,EAAE,CAAC,CAAC;IAC3G,IAAI,EAAE,cAAc,SAAS,CAAC,IAAI,EAAE;IACpC,QAAQ;IACR,MAAM,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;IACrB,SAAS,EAAE;QACT,kBAAkB,EAAE;YAClB,KAAK,EAAE,SAAS,CAAC,KAAK;YACtB,gBAAgB,EAAE,IAAI;YACtB,kBAAkB,EAAE,SAAS,CAAC,iBAAiB;gBAC7C,CAAC,CAAC;oBACE,kBAAkB,EAAE;wBAClB,YAAY,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;wBAC7B,oBAAoB,EAAE,aAAa;wBACnC,YAAY,EAAE,SAAS,CAAC,iBAAiB;wBACzC,mBAAmB,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;qBACrD;iBACF;gBACH,CAAC,CAAC,SAAS;SACd;KACF;IACD,gBAAgB,EAAE;QAChB,wBAAwB,EAAE,IAAI;QAC9B,UAAU,EAAE,cAAc,SAAS,CAAC,IAAI,EAAE;QAC1C,sBAAsB,EAAE,IAAI;KAC7B;CACF,CAAC,CAAC;AAEH,mFAAmF;AACnF,wEAAwE;AACjE,MAAM,gBAAgB,GAAG,CAAC,SAAuC,EAAsC,EAAE;IAC9G,MAAM,cAAc,GAAG,CAAC,SAAS,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE,CAAC,kBAAkB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;IAEpH,MAAM,YAAY,GAAG,CAAC,SAAS,CAAC,iBAAiB,IAAI,wBAAwB,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE,CACtG,yBAAyB,CAAC,SAAS,EAAE,cAAc,CAAC,MAAM,GAAG,KAAK,CAAC,CACpE,CAAC;IAEF,OAAO,CAAC,GAAG,cAAc,EAAE,GAAG,YAAY,CAAC,CAAC;AAC9C,CAAC,CAAC;AARW,QAAA,gBAAgB,oBAQ3B","sourcesContent":["import { BootstrapWafQPQConfigSetting, WafManagedRuleGroup, WafRateLimit } from 'quidproquo-config-aws';\n\nimport { aws_wafv2 } from 'aws-cdk-lib';\n\nconst managedRuleGroupVendorNames: Record<WafManagedRuleGroup, string> = {\n [WafManagedRuleGroup.common]: 'AWSManagedRulesCommonRuleSet',\n [WafManagedRuleGroup.knownBadInputs]: 'AWSManagedRulesKnownBadInputsRuleSet',\n [WafManagedRuleGroup.sqli]: 'AWSManagedRulesSQLiRuleSet',\n [WafManagedRuleGroup.ipReputation]: 'AWSManagedRulesAmazonIpReputationList',\n};\n\nconst defaultManagedRuleGroups: WafManagedRuleGroup[] = [WafManagedRuleGroup.common, WafManagedRuleGroup.knownBadInputs, WafManagedRuleGroup.sqli];\n\nconst buildManagedRuleGroupRule = (ruleGroup: WafManagedRuleGroup, priority: number): aws_wafv2.CfnWebACL.RuleProperty => {\n const vendorName = managedRuleGroupVendorNames[ruleGroup];\n\n return {\n name: vendorName,\n priority,\n overrideAction: { none: {} },\n statement: {\n managedRuleGroupStatement: {\n vendorName: 'AWS',\n name: vendorName,\n },\n },\n visibilityConfig: {\n cloudWatchMetricsEnabled: true,\n metricName: vendorName,\n sampledRequestsEnabled: true,\n },\n };\n};\n\nconst buildRateLimitRule = (rateLimit: WafRateLimit, priority: number): aws_wafv2.CfnWebACL.RuleProperty => ({\n name: `rate-limit-${rateLimit.name}`,\n priority,\n action: { block: {} },\n statement: {\n rateBasedStatement: {\n limit: rateLimit.limit,\n aggregateKeyType: 'IP',\n scopeDownStatement: rateLimit.uriPathStartsWith\n ? {\n byteMatchStatement: {\n fieldToMatch: { uriPath: {} },\n positionalConstraint: 'STARTS_WITH',\n searchString: rateLimit.uriPathStartsWith,\n textTransformations: [{ priority: 0, type: 'NONE' }],\n },\n }\n : undefined,\n },\n },\n visibilityConfig: {\n cloudWatchMetricsEnabled: true,\n metricName: `rate-limit-${rateLimit.name}`,\n sampledRequestsEnabled: true,\n },\n});\n\n// Shared by the REGIONAL and CLOUDFRONT web acls so both evaluate identical rules.\n// Rate limits run first (cheap counters), then the managed rule groups.\nexport const buildWebAclRules = (wafConfig: BootstrapWafQPQConfigSetting): aws_wafv2.CfnWebACL.RuleProperty[] => {\n const rateLimitRules = (wafConfig.rateLimits || []).map((rateLimit, index) => buildRateLimitRule(rateLimit, index));\n\n const managedRules = (wafConfig.managedRuleGroups || defaultManagedRuleGroups).map((ruleGroup, index) =>\n buildManagedRuleGroupRule(ruleGroup, rateLimitRules.length + index),\n );\n\n return [...rateLimitRules, ...managedRules];\n};\n"]}
1
+ {"version":3,"file":"wafRules.js","sourceRoot":"","sources":["../../../../../../src/constructs/feature/config/waf/wafRules.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BootstrapWafQPQConfigSetting,\n WafManagedRuleGroup,\n WafManagedRuleOverride,\n WafRateLimit,\n WafRuleOverrideAction,\n} from 'quidproquo-config-aws';\n\nimport { aws_wafv2 } from 'aws-cdk-lib';\n\nconst managedRuleGroupVendorNames: Record<WafManagedRuleGroup, string> = {\n [WafManagedRuleGroup.common]: 'AWSManagedRulesCommonRuleSet',\n [WafManagedRuleGroup.knownBadInputs]: 'AWSManagedRulesKnownBadInputsRuleSet',\n [WafManagedRuleGroup.sqli]: 'AWSManagedRulesSQLiRuleSet',\n [WafManagedRuleGroup.ipReputation]: 'AWSManagedRulesAmazonIpReputationList',\n};\n\nconst defaultManagedRuleGroups: WafManagedRuleGroup[] = [WafManagedRuleGroup.common, WafManagedRuleGroup.knownBadInputs, WafManagedRuleGroup.sqli];\n\nconst overrideActionsToUse: Record<WafRuleOverrideAction, aws_wafv2.CfnWebACL.RuleActionProperty> = {\n [WafRuleOverrideAction.count]: { count: {} },\n};\n\nconst buildManagedRuleGroupRule = (\n ruleGroup: WafManagedRuleGroup,\n priority: number,\n overrides?: WafManagedRuleOverride[],\n): aws_wafv2.CfnWebACL.RuleProperty => {\n const vendorName = managedRuleGroupVendorNames[ruleGroup];\n\n const ruleActionOverrides = overrides?.length\n ? overrides.map((override) => ({\n name: override.name,\n actionToUse: overrideActionsToUse[override.action],\n }))\n : undefined;\n\n return {\n name: vendorName,\n priority,\n overrideAction: { none: {} },\n statement: {\n managedRuleGroupStatement: {\n vendorName: 'AWS',\n name: vendorName,\n ruleActionOverrides,\n },\n },\n visibilityConfig: {\n cloudWatchMetricsEnabled: true,\n metricName: vendorName,\n sampledRequestsEnabled: true,\n },\n };\n};\n\nconst buildRateLimitRule = (rateLimit: WafRateLimit, priority: number): aws_wafv2.CfnWebACL.RuleProperty => ({\n name: `rate-limit-${rateLimit.name}`,\n priority,\n action: { block: {} },\n statement: {\n rateBasedStatement: {\n limit: rateLimit.limit,\n aggregateKeyType: 'IP',\n scopeDownStatement: rateLimit.uriPathStartsWith\n ? {\n byteMatchStatement: {\n fieldToMatch: { uriPath: {} },\n positionalConstraint: 'STARTS_WITH',\n searchString: rateLimit.uriPathStartsWith,\n textTransformations: [{ priority: 0, type: 'NONE' }],\n },\n }\n : undefined,\n },\n },\n visibilityConfig: {\n cloudWatchMetricsEnabled: true,\n metricName: `rate-limit-${rateLimit.name}`,\n sampledRequestsEnabled: true,\n },\n});\n\n// Shared by the REGIONAL and CLOUDFRONT web acls so both evaluate identical rules.\n// Rate limits run first (cheap counters), then the managed rule groups.\nexport const buildWebAclRules = (wafConfig: BootstrapWafQPQConfigSetting): aws_wafv2.CfnWebACL.RuleProperty[] => {\n const rateLimitRules = (wafConfig.rateLimits || []).map((rateLimit, index) => buildRateLimitRule(rateLimit, index));\n\n const managedRules = (wafConfig.managedRuleGroups || defaultManagedRuleGroups).map((ruleGroup, index) =>\n buildManagedRuleGroupRule(ruleGroup, rateLimitRules.length + index, wafConfig.managedRuleOverrides?.[ruleGroup]),\n );\n\n return [...rateLimitRules, ...managedRules];\n};\n"]}
@@ -17,5 +17,5 @@ export declare class QpqCoreKeyValueStoreConstruct extends QpqCoreKeyValueStoreC
17
17
  table: aws_dynamodb.ITable;
18
18
  static fromOtherStack(scope: Construct, id: string, qpqConfig: QPQConfig, keyValueStoreName: string): QpqCoreKeyValueStoreConstructBase;
19
19
  constructor(scope: Construct, id: string, props: QpqCoreKeyValueStoreConstructProps);
20
- static authorizeActionsForRole(role: aws_iam.IRole, qpqConfig: QPQConfig, ownedKvsList: QpqCoreKeyValueStoreConstruct[]): void;
20
+ static authorizeActionsForRole(scope: Construct, role: aws_iam.IRole, qpqConfig: QPQConfig, ownedKvsList: QpqCoreKeyValueStoreConstruct[]): void;
21
21
  }
@@ -155,7 +155,7 @@ class QpqCoreKeyValueStoreConstruct extends QpqCoreKeyValueStoreConstructBase {
155
155
  this.table = aws_cdk_lib_1.aws_dynamodb.Table.fromTableName(this, 'tablelink', tableNameOverride);
156
156
  }
157
157
  }
158
- static authorizeActionsForRole(role, qpqConfig, ownedKvsList) {
158
+ static authorizeActionsForRole(scope, role, qpqConfig, ownedKvsList) {
159
159
  // CDK-known ARNs for tables created in this stack (+ GSI ARNs).
160
160
  const ownedArns = ownedKvsList.flatMap((kvs) => [kvs.table.tableArn, `${kvs.table.tableArn}/index/*`]);
161
161
  // Deterministically-computed ARNs for KVSs declared in this service's
@@ -172,11 +172,7 @@ class QpqCoreKeyValueStoreConstruct extends QpqCoreKeyValueStoreConstructBase {
172
172
  const resources = [...ownedArns, ...foreignArns];
173
173
  if (resources.length === 0)
174
174
  return;
175
- role.addToPrincipalPolicy(new aws_cdk_lib_1.aws_iam.PolicyStatement({
176
- effect: aws_cdk_lib_1.aws_iam.Effect.ALLOW,
177
- actions: ['dynamodb:GetItem', 'dynamodb:PutItem', 'dynamodb:Query', 'dynamodb:Scan', 'dynamodb:UpdateItem', 'dynamodb:DeleteItem'],
178
- resources,
179
- }));
175
+ qpqDeployAwsCdkUtils.attachManagedResourcePolicies(scope, role, 'webserverKeyValueStoreAccess', ['dynamodb:GetItem', 'dynamodb:PutItem', 'dynamodb:Query', 'dynamodb:Scan', 'dynamodb:UpdateItem', 'dynamodb:DeleteItem'], resources);
180
176
  // Grant KMS permissions for any encrypted KVSs (owned or foreign) whose
181
177
  // customer-managed key is declared in this service's config.
182
178
  const kmsArns = [...ownedKvsConfigs, ...foreignKvsConfigs]
@@ -1 +1 @@
1
- {"version":3,"file":"QpqCoreKeyValueStoreConstruct.js","sourceRoot":"","sources":["../../../../../../src/constructs/feature/core/keyValueStore/QpqCoreKeyValueStoreConstruct.ts"],"names":[],"mappings":"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","sourcesContent":["import { awsNamingUtils } from 'quidproquo-actionprocessor-awslambda';\nimport { AwsDataStoreRemovalPolicy, qpqConfigAwsUtils } from 'quidproquo-config-aws';\nimport { KeyValueStoreQPQConfigSetting, KvsKey, QPQConfig, qpqCoreUtils } from 'quidproquo-core';\n\nimport { aws_dynamodb, aws_iam, aws_kms } from 'aws-cdk-lib';\nimport * as cdk from 'aws-cdk-lib';\nimport { Construct } from 'constructs';\n\nimport * as qpqDeployAwsCdkUtils from '../../../../utils/qpqDeployAwsCdkUtils';\nimport { createDefaultResourceAlarm } from '../../../base/createDefaultResourceAlarm';\nimport { QpqConstructBlock, QpqConstructBlockProps } from '../../../base/QpqConstructBlock';\n\nexport interface QpqCoreKeyValueStoreConstructProps extends QpqConstructBlockProps {\n keyValueStoreConfig: KeyValueStoreQPQConfigSetting;\n}\n\nexport abstract class QpqCoreKeyValueStoreConstructBase extends QpqConstructBlock {\n abstract table: aws_dynamodb.ITable;\n\n public grantRead(grantee: aws_iam.IGrantable) {\n this.table.grantReadData(grantee);\n }\n\n public grantWrite(grantee: aws_iam.IGrantable) {\n this.table.grantWriteData(grantee);\n }\n\n public grantAll(grantee: aws_iam.IGrantable) {\n this.table.grantFullAccess(grantee);\n }\n}\n\nexport const convertKvsKeyTypeToDynamodbAttributeType = (kvsKeyType: KvsKey['type']): aws_dynamodb.AttributeType => {\n switch (kvsKeyType) {\n case 'string':\n return aws_dynamodb.AttributeType.STRING;\n case 'number':\n return aws_dynamodb.AttributeType.NUMBER;\n case 'binary':\n return aws_dynamodb.AttributeType.BINARY;\n }\n\n throw new Error(`Unknown KvsKeyType: ${kvsKeyType}`);\n};\n\nexport const convertKvsKeyToDynamodbAttribute = (kvsKey: KvsKey): aws_dynamodb.Attribute => ({\n name: kvsKey.key,\n type: convertKvsKeyTypeToDynamodbAttributeType(kvsKey.type),\n});\n\nexport class QpqCoreKeyValueStoreConstruct extends QpqCoreKeyValueStoreConstructBase {\n table: aws_dynamodb.ITable;\n\n static fromOtherStack(scope: Construct, id: string, qpqConfig: QPQConfig, keyValueStoreName: string): QpqCoreKeyValueStoreConstructBase {\n const tableNameOverride = qpqConfigAwsUtils.getDynamoTableNameOverrride(keyValueStoreName, qpqConfig);\n\n class Import extends QpqCoreKeyValueStoreConstructBase {\n table = aws_dynamodb.Table.fromTableName(this, 'table', tableNameOverride || this.qpqResourceName(keyValueStoreName, 'kvs'));\n }\n\n return new Import(scope, id, { qpqConfig });\n }\n\n constructor(scope: Construct, id: string, props: QpqCoreKeyValueStoreConstructProps) {\n super(scope, id, props);\n\n const dataStoreRemovalPolicy = qpqConfigAwsUtils.getAwsDataStoreRemovalPolicy(props.qpqConfig);\n\n const [primarySortKey] = props.keyValueStoreConfig.sortKeys;\n\n let tableEncryption: aws_dynamodb.TableEncryption | undefined;\n let encryptionKey: aws_kms.IKey | undefined;\n if (props.keyValueStoreConfig.encryption) {\n const kmsCfg = qpqConfigAwsUtils.getAwsKmsKeyForKeyValueStore(props.qpqConfig, props.keyValueStoreConfig);\n if (kmsCfg) {\n encryptionKey = aws_kms.Key.fromKeyArn(this, 'enc-key', kmsCfg.arn);\n tableEncryption = aws_dynamodb.TableEncryption.CUSTOMER_MANAGED;\n } else {\n tableEncryption = aws_dynamodb.TableEncryption.AWS_MANAGED;\n }\n }\n\n const table = new aws_dynamodb.Table(this, 'table', {\n tableName: this.qpqResourceName(props.keyValueStoreConfig.keyValueStoreName, 'kvs'),\n partitionKey: convertKvsKeyToDynamodbAttribute(props.keyValueStoreConfig.partitionKey),\n sortKey: primarySortKey && convertKvsKeyToDynamodbAttribute(primarySortKey),\n billingMode: aws_dynamodb.BillingMode.PAY_PER_REQUEST,\n // Retain data stores by default; dev configs opt into full teardown via defineAwsDataStoreRemovalPolicy(destroy).\n // When retained, deletionProtection also blocks deletes/replacements outright (RETAIN alone only orphans the table).\n removalPolicy: dataStoreRemovalPolicy === AwsDataStoreRemovalPolicy.destroy ? cdk.RemovalPolicy.DESTROY : cdk.RemovalPolicy.RETAIN,\n deletionProtection: dataStoreRemovalPolicy === AwsDataStoreRemovalPolicy.retain,\n timeToLiveAttribute: props.keyValueStoreConfig.ttlAttribute,\n // PITR on by default (35-day continuous backups / point-in-time restore); opt out per-table via config.\n pointInTimeRecoverySpecification: { pointInTimeRecoveryEnabled: !props.keyValueStoreConfig.disablePointInTimeRecovery },\n encryption: tableEncryption,\n encryptionKey,\n });\n\n qpqDeployAwsCdkUtils.applyEnvironmentTags(table, props.qpqConfig);\n\n // Default alarms (opt-in via defineNotifyError): read/write throttling means\n // the table is rejecting requests (hot partition / capacity), user-visible.\n createDefaultResourceAlarm(this, props.qpqConfig, {\n id: 'default-alarm-read-throttle',\n alarmName: this.resourceName(`${props.keyValueStoreConfig.keyValueStoreName}-read-throttle`),\n metric: table.metric('ReadThrottleEvents', { period: cdk.Duration.minutes(1), statistic: 'Sum' }),\n threshold: 1,\n evaluationPeriods: 1,\n });\n createDefaultResourceAlarm(this, props.qpqConfig, {\n id: 'default-alarm-write-throttle',\n alarmName: this.resourceName(`${props.keyValueStoreConfig.keyValueStoreName}-write-throttle`),\n metric: table.metric('WriteThrottleEvents', { period: cdk.Duration.minutes(1), statistic: 'Sum' }),\n threshold: 1,\n evaluationPeriods: 1,\n });\n\n // Do local secondary indexes\n for (let i = 1; i < props.keyValueStoreConfig.sortKeys.length; i++) {\n let sortKey = props.keyValueStoreConfig.sortKeys[i];\n\n table.addLocalSecondaryIndex({\n indexName: sortKey.key,\n sortKey: convertKvsKeyToDynamodbAttribute(sortKey),\n });\n }\n\n // Do global secondary indexes\n for (const index of props.keyValueStoreConfig.indexes) {\n table.addGlobalSecondaryIndex({\n indexName: index.partitionKey.key,\n partitionKey: convertKvsKeyToDynamodbAttribute(index.partitionKey),\n sortKey: index.sortKey && convertKvsKeyToDynamodbAttribute(index.sortKey),\n });\n }\n\n this.table = table;\n\n // If we have an override, lets use it instead\n // we still want to keep the above table created.\n const tableNameOverride = qpqConfigAwsUtils.getDynamoTableNameOverrride(props.keyValueStoreConfig.keyValueStoreName, props.qpqConfig);\n if (tableNameOverride) {\n console.log('tableNameOverride', tableNameOverride);\n this.table = aws_dynamodb.Table.fromTableName(this, 'tablelink', tableNameOverride);\n }\n }\n\n public static authorizeActionsForRole(role: aws_iam.IRole, qpqConfig: QPQConfig, ownedKvsList: QpqCoreKeyValueStoreConstruct[]) {\n // CDK-known ARNs for tables created in this stack (+ GSI ARNs).\n const ownedArns = ownedKvsList.flatMap((kvs) => [kvs.table.tableArn, `${kvs.table.tableArn}/index/*`]);\n\n // Deterministically-computed ARNs for KVSs declared in this service's\n // config but owned by another service. Uses the same naming path as\n // `getKvsDynamoTableNameFromConfig` so no CDK cross-stack ref is created.\n const allKvsConfigs = qpqCoreUtils.getAllKeyValueStores(qpqConfig);\n const ownedKvsConfigs = qpqCoreUtils.getOwnedKeyValueStores(qpqConfig);\n const foreignKvsConfigs = allKvsConfigs.filter((cfg) => !ownedKvsConfigs.includes(cfg));\n\n const foreignArns = foreignKvsConfigs.flatMap((cfg) => {\n const tableName = awsNamingUtils.getKvsDynamoTableNameFromConfig(cfg.keyValueStoreName, qpqConfig, 'kvs');\n const tableArn = `arn:aws:dynamodb:*:*:table/${tableName}`;\n return [tableArn, `${tableArn}/index/*`];\n });\n\n const resources = [...ownedArns, ...foreignArns];\n if (resources.length === 0) return;\n\n role.addToPrincipalPolicy(\n new aws_iam.PolicyStatement({\n effect: aws_iam.Effect.ALLOW,\n actions: ['dynamodb:GetItem', 'dynamodb:PutItem', 'dynamodb:Query', 'dynamodb:Scan', 'dynamodb:UpdateItem', 'dynamodb:DeleteItem'],\n resources,\n }),\n );\n\n // Grant KMS permissions for any encrypted KVSs (owned or foreign) whose\n // customer-managed key is declared in this service's config.\n const kmsArns = [...ownedKvsConfigs, ...foreignKvsConfigs]\n .filter((cfg) => cfg.encryption)\n .map((cfg) => qpqConfigAwsUtils.getAwsKmsKeyForKeyValueStore(qpqConfig, cfg)?.arn)\n .filter((arn): arn is string => Boolean(arn));\n\n if (kmsArns.length > 0) {\n role.addToPrincipalPolicy(\n new aws_iam.PolicyStatement({\n effect: aws_iam.Effect.ALLOW,\n actions: ['kms:Decrypt', 'kms:GenerateDataKey*', 'kms:DescribeKey', 'kms:Encrypt', 'kms:ReEncrypt*'],\n resources: [...new Set(kmsArns)],\n }),\n );\n }\n }\n}\n"]}
1
+ {"version":3,"file":"QpqCoreKeyValueStoreConstruct.js","sourceRoot":"","sources":["../../../../../../src/constructs/feature/core/keyValueStore/QpqCoreKeyValueStoreConstruct.ts"],"names":[],"mappings":"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","sourcesContent":["import { awsNamingUtils } from 'quidproquo-actionprocessor-awslambda';\nimport { AwsDataStoreRemovalPolicy, qpqConfigAwsUtils } from 'quidproquo-config-aws';\nimport { KeyValueStoreQPQConfigSetting, KvsKey, QPQConfig, qpqCoreUtils } from 'quidproquo-core';\n\nimport { aws_dynamodb, aws_iam, aws_kms } from 'aws-cdk-lib';\nimport * as cdk from 'aws-cdk-lib';\nimport { Construct } from 'constructs';\n\nimport * as qpqDeployAwsCdkUtils from '../../../../utils/qpqDeployAwsCdkUtils';\nimport { createDefaultResourceAlarm } from '../../../base/createDefaultResourceAlarm';\nimport { QpqConstructBlock, QpqConstructBlockProps } from '../../../base/QpqConstructBlock';\n\nexport interface QpqCoreKeyValueStoreConstructProps extends QpqConstructBlockProps {\n keyValueStoreConfig: KeyValueStoreQPQConfigSetting;\n}\n\nexport abstract class QpqCoreKeyValueStoreConstructBase extends QpqConstructBlock {\n abstract table: aws_dynamodb.ITable;\n\n public grantRead(grantee: aws_iam.IGrantable) {\n this.table.grantReadData(grantee);\n }\n\n public grantWrite(grantee: aws_iam.IGrantable) {\n this.table.grantWriteData(grantee);\n }\n\n public grantAll(grantee: aws_iam.IGrantable) {\n this.table.grantFullAccess(grantee);\n }\n}\n\nexport const convertKvsKeyTypeToDynamodbAttributeType = (kvsKeyType: KvsKey['type']): aws_dynamodb.AttributeType => {\n switch (kvsKeyType) {\n case 'string':\n return aws_dynamodb.AttributeType.STRING;\n case 'number':\n return aws_dynamodb.AttributeType.NUMBER;\n case 'binary':\n return aws_dynamodb.AttributeType.BINARY;\n }\n\n throw new Error(`Unknown KvsKeyType: ${kvsKeyType}`);\n};\n\nexport const convertKvsKeyToDynamodbAttribute = (kvsKey: KvsKey): aws_dynamodb.Attribute => ({\n name: kvsKey.key,\n type: convertKvsKeyTypeToDynamodbAttributeType(kvsKey.type),\n});\n\nexport class QpqCoreKeyValueStoreConstruct extends QpqCoreKeyValueStoreConstructBase {\n table: aws_dynamodb.ITable;\n\n static fromOtherStack(scope: Construct, id: string, qpqConfig: QPQConfig, keyValueStoreName: string): QpqCoreKeyValueStoreConstructBase {\n const tableNameOverride = qpqConfigAwsUtils.getDynamoTableNameOverrride(keyValueStoreName, qpqConfig);\n\n class Import extends QpqCoreKeyValueStoreConstructBase {\n table = aws_dynamodb.Table.fromTableName(this, 'table', tableNameOverride || this.qpqResourceName(keyValueStoreName, 'kvs'));\n }\n\n return new Import(scope, id, { qpqConfig });\n }\n\n constructor(scope: Construct, id: string, props: QpqCoreKeyValueStoreConstructProps) {\n super(scope, id, props);\n\n const dataStoreRemovalPolicy = qpqConfigAwsUtils.getAwsDataStoreRemovalPolicy(props.qpqConfig);\n\n const [primarySortKey] = props.keyValueStoreConfig.sortKeys;\n\n let tableEncryption: aws_dynamodb.TableEncryption | undefined;\n let encryptionKey: aws_kms.IKey | undefined;\n if (props.keyValueStoreConfig.encryption) {\n const kmsCfg = qpqConfigAwsUtils.getAwsKmsKeyForKeyValueStore(props.qpqConfig, props.keyValueStoreConfig);\n if (kmsCfg) {\n encryptionKey = aws_kms.Key.fromKeyArn(this, 'enc-key', kmsCfg.arn);\n tableEncryption = aws_dynamodb.TableEncryption.CUSTOMER_MANAGED;\n } else {\n tableEncryption = aws_dynamodb.TableEncryption.AWS_MANAGED;\n }\n }\n\n const table = new aws_dynamodb.Table(this, 'table', {\n tableName: this.qpqResourceName(props.keyValueStoreConfig.keyValueStoreName, 'kvs'),\n partitionKey: convertKvsKeyToDynamodbAttribute(props.keyValueStoreConfig.partitionKey),\n sortKey: primarySortKey && convertKvsKeyToDynamodbAttribute(primarySortKey),\n billingMode: aws_dynamodb.BillingMode.PAY_PER_REQUEST,\n // Retain data stores by default; dev configs opt into full teardown via defineAwsDataStoreRemovalPolicy(destroy).\n // When retained, deletionProtection also blocks deletes/replacements outright (RETAIN alone only orphans the table).\n removalPolicy: dataStoreRemovalPolicy === AwsDataStoreRemovalPolicy.destroy ? cdk.RemovalPolicy.DESTROY : cdk.RemovalPolicy.RETAIN,\n deletionProtection: dataStoreRemovalPolicy === AwsDataStoreRemovalPolicy.retain,\n timeToLiveAttribute: props.keyValueStoreConfig.ttlAttribute,\n // PITR on by default (35-day continuous backups / point-in-time restore); opt out per-table via config.\n pointInTimeRecoverySpecification: { pointInTimeRecoveryEnabled: !props.keyValueStoreConfig.disablePointInTimeRecovery },\n encryption: tableEncryption,\n encryptionKey,\n });\n\n qpqDeployAwsCdkUtils.applyEnvironmentTags(table, props.qpqConfig);\n\n // Default alarms (opt-in via defineNotifyError): read/write throttling means\n // the table is rejecting requests (hot partition / capacity), user-visible.\n createDefaultResourceAlarm(this, props.qpqConfig, {\n id: 'default-alarm-read-throttle',\n alarmName: this.resourceName(`${props.keyValueStoreConfig.keyValueStoreName}-read-throttle`),\n metric: table.metric('ReadThrottleEvents', { period: cdk.Duration.minutes(1), statistic: 'Sum' }),\n threshold: 1,\n evaluationPeriods: 1,\n });\n createDefaultResourceAlarm(this, props.qpqConfig, {\n id: 'default-alarm-write-throttle',\n alarmName: this.resourceName(`${props.keyValueStoreConfig.keyValueStoreName}-write-throttle`),\n metric: table.metric('WriteThrottleEvents', { period: cdk.Duration.minutes(1), statistic: 'Sum' }),\n threshold: 1,\n evaluationPeriods: 1,\n });\n\n // Do local secondary indexes\n for (let i = 1; i < props.keyValueStoreConfig.sortKeys.length; i++) {\n let sortKey = props.keyValueStoreConfig.sortKeys[i];\n\n table.addLocalSecondaryIndex({\n indexName: sortKey.key,\n sortKey: convertKvsKeyToDynamodbAttribute(sortKey),\n });\n }\n\n // Do global secondary indexes\n for (const index of props.keyValueStoreConfig.indexes) {\n table.addGlobalSecondaryIndex({\n indexName: index.partitionKey.key,\n partitionKey: convertKvsKeyToDynamodbAttribute(index.partitionKey),\n sortKey: index.sortKey && convertKvsKeyToDynamodbAttribute(index.sortKey),\n });\n }\n\n this.table = table;\n\n // If we have an override, lets use it instead\n // we still want to keep the above table created.\n const tableNameOverride = qpqConfigAwsUtils.getDynamoTableNameOverrride(props.keyValueStoreConfig.keyValueStoreName, props.qpqConfig);\n if (tableNameOverride) {\n console.log('tableNameOverride', tableNameOverride);\n this.table = aws_dynamodb.Table.fromTableName(this, 'tablelink', tableNameOverride);\n }\n }\n\n public static authorizeActionsForRole(scope: Construct, role: aws_iam.IRole, qpqConfig: QPQConfig, ownedKvsList: QpqCoreKeyValueStoreConstruct[]) {\n // CDK-known ARNs for tables created in this stack (+ GSI ARNs).\n const ownedArns = ownedKvsList.flatMap((kvs) => [kvs.table.tableArn, `${kvs.table.tableArn}/index/*`]);\n\n // Deterministically-computed ARNs for KVSs declared in this service's\n // config but owned by another service. Uses the same naming path as\n // `getKvsDynamoTableNameFromConfig` so no CDK cross-stack ref is created.\n const allKvsConfigs = qpqCoreUtils.getAllKeyValueStores(qpqConfig);\n const ownedKvsConfigs = qpqCoreUtils.getOwnedKeyValueStores(qpqConfig);\n const foreignKvsConfigs = allKvsConfigs.filter((cfg) => !ownedKvsConfigs.includes(cfg));\n\n const foreignArns = foreignKvsConfigs.flatMap((cfg) => {\n const tableName = awsNamingUtils.getKvsDynamoTableNameFromConfig(cfg.keyValueStoreName, qpqConfig, 'kvs');\n const tableArn = `arn:aws:dynamodb:*:*:table/${tableName}`;\n return [tableArn, `${tableArn}/index/*`];\n });\n\n const resources = [...ownedArns, ...foreignArns];\n if (resources.length === 0) return;\n\n qpqDeployAwsCdkUtils.attachManagedResourcePolicies(\n scope,\n role,\n 'webserverKeyValueStoreAccess',\n ['dynamodb:GetItem', 'dynamodb:PutItem', 'dynamodb:Query', 'dynamodb:Scan', 'dynamodb:UpdateItem', 'dynamodb:DeleteItem'],\n resources,\n );\n\n // Grant KMS permissions for any encrypted KVSs (owned or foreign) whose\n // customer-managed key is declared in this service's config.\n const kmsArns = [...ownedKvsConfigs, ...foreignKvsConfigs]\n .filter((cfg) => cfg.encryption)\n .map((cfg) => qpqConfigAwsUtils.getAwsKmsKeyForKeyValueStore(qpqConfig, cfg)?.arn)\n .filter((arn): arn is string => Boolean(arn));\n\n if (kmsArns.length > 0) {\n role.addToPrincipalPolicy(\n new aws_iam.PolicyStatement({\n effect: aws_iam.Effect.ALLOW,\n actions: ['kms:Decrypt', 'kms:GenerateDataKey*', 'kms:DescribeKey', 'kms:Encrypt', 'kms:ReEncrypt*'],\n resources: [...new Set(kmsArns)],\n }),\n );\n }\n }\n}\n"]}
@@ -16,5 +16,5 @@ export declare class QpqCoreParameterConstruct extends QpqCoreParameterConstruct
16
16
  stringParameter: aws_ssm.IStringParameter;
17
17
  static fromOtherStack(scope: Construct, id: string, qpqConfig: QPQConfig, parameterConfig: ParameterQPQConfigSetting): QpqResource;
18
18
  constructor(scope: Construct, id: string, props: QpqCoreParameterConstructProps);
19
- static authorizeActionsForRole(role: aws_iam.IRole, parameterConfigs: ParameterQPQConfigSetting[], qpqConfig: QPQConfig): void;
19
+ static authorizeActionsForRole(scope: Construct, role: aws_iam.IRole, parameterConfigs: ParameterQPQConfigSetting[], qpqConfig: QPQConfig): void;
20
20
  }
@@ -74,18 +74,16 @@ class QpqCoreParameterConstruct extends QpqCoreParameterConstructBase {
74
74
  });
75
75
  qpqDeployAwsCdkUtils.applyEnvironmentTags(this.stringParameter, props.qpqConfig);
76
76
  }
77
- static authorizeActionsForRole(role, parameterConfigs, qpqConfig) {
78
- if (parameterConfigs.length > 0) {
79
- role.addToPrincipalPolicy(new aws_cdk_lib_1.aws_iam.PolicyStatement({
80
- effect: aws_cdk_lib_1.aws_iam.Effect.ALLOW,
81
- actions: ['ssm:GetParameter', 'ssm:GetParameters', 'ssm:DescribeParameters'],
82
- resources: parameterConfigs.map((parameterConfig) => {
83
- const { awsRegion, awsAccountId } = (0, quidproquo_config_aws_1.resolveAwsServiceAccountInfo)(qpqConfig, parameterConfig.owner);
84
- const paramName = quidproquo_actionprocessor_awslambda_1.awsNamingUtils.resolveConfigRuntimeResourceNameFromConfig(parameterConfig.key, qpqConfig, parameterConfig.owner);
85
- return `arn:aws:ssm:${awsRegion}:${awsAccountId}:parameter/${paramName}`;
86
- }),
87
- }));
88
- }
77
+ static authorizeActionsForRole(scope, role, parameterConfigs, qpqConfig) {
78
+ const resources = parameterConfigs.map((parameterConfig) => {
79
+ const { awsRegion, awsAccountId } = (0, quidproquo_config_aws_1.resolveAwsServiceAccountInfo)(qpqConfig, parameterConfig.owner);
80
+ const paramName = quidproquo_actionprocessor_awslambda_1.awsNamingUtils.resolveConfigRuntimeResourceNameFromConfig(parameterConfig.key, qpqConfig, parameterConfig.owner);
81
+ return `arn:aws:ssm:${awsRegion}:${awsAccountId}:parameter/${paramName}`;
82
+ });
83
+ if (resources.length === 0)
84
+ return;
85
+ // Off the inline DefaultPolicy (10,240-byte cap) onto managed policies.
86
+ qpqDeployAwsCdkUtils.attachManagedResourcePolicies(scope, role, 'webserverParameterAccess', ['ssm:GetParameter', 'ssm:GetParameters', 'ssm:DescribeParameters'], resources);
89
87
  }
90
88
  }
91
89
  exports.QpqCoreParameterConstruct = QpqCoreParameterConstruct;
@@ -1 +1 @@
1
- {"version":3,"file":"QpqCoreParameterConstruct.js","sourceRoot":"","sources":["../../../../../../src/constructs/feature/core/parameter/QpqCoreParameterConstruct.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+FAAsE;AACtE,iEAAqE;AAGrE,6CAA+C;AAG/C,wEAA0D;AAC1D,uEAA4F;AAO5F,MAAsB,6BAA8B,SAAQ,qCAAiB;IAGpE,SAAS,CAAC,OAA2B;QAC1C,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IAEM,UAAU,CAAC,OAA2B;QAC3C,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAC3C,CAAC;IAEM,QAAQ,CAAC,OAA2B;QACzC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;CACF;AAfD,sEAeC;AAED,MAAa,yBAA0B,SAAQ,6BAA6B;IAG1E,MAAM,CAAC,cAAc,CAAC,KAAgB,EAAE,EAAU,EAAE,SAAoB,EAAE,eAA0C;QAClH,MAAM,SAAS,GAAG,qDAAc,CAAC,0CAA0C,CAAC,eAAe,CAAC,GAAG,EAAE,SAAS,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC;QAEnI,MAAM,MAAO,SAAQ,6BAA6B;YAAlD;;gBACE,oBAAe,GAAG,qBAAO,CAAC,eAAe,CAAC,uBAAuB,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,eAAe,CAAC,SAAS,EAAE,EAAE,SAAS,CAAC,CAAC;YAC5H,CAAC;SAAA;QAED,OAAO,IAAI,MAAM,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,YAAY,KAAgB,EAAE,EAAU,EAAE,KAAqC;QAC7E,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;QAExB,IAAI,CAAC,eAAe,GAAG,IAAI,qBAAO,CAAC,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE;YAChE,aAAa,EAAE,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC;YAC3D,WAAW,EAAE,KAAK,CAAC,eAAe,CAAC,GAAG;YACtC,WAAW,EAAE,KAAK,CAAC,eAAe,CAAC,KAAK,IAAI,oBAAoB;YAEhE,oCAAoC;YACpC,IAAI,EAAE,qBAAO,CAAC,aAAa,CAAC,QAAQ;SACrC,CAAC,CAAC;QAEH,oBAAoB,CAAC,oBAAoB,CAAC,IAAI,CAAC,eAAe,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IACnF,CAAC;IAEM,MAAM,CAAC,uBAAuB,CAAC,IAAmB,EAAE,gBAA6C,EAAE,SAAoB;QAC5H,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChC,IAAI,CAAC,oBAAoB,CACvB,IAAI,qBAAO,CAAC,eAAe,CAAC;gBAC1B,MAAM,EAAE,qBAAO,CAAC,MAAM,CAAC,KAAK;gBAC5B,OAAO,EAAE,CAAC,kBAAkB,EAAE,mBAAmB,EAAE,wBAAwB,CAAC;gBAC5E,SAAS,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAC,eAAe,EAAE,EAAE;oBAClD,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,IAAA,oDAA4B,EAAC,SAAS,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC;oBAEnG,MAAM,SAAS,GAAG,qDAAc,CAAC,0CAA0C,CAAC,eAAe,CAAC,GAAG,EAAE,SAAS,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC;oBAEnI,OAAO,eAAe,SAAS,IAAI,YAAY,cAAc,SAAS,EAAE,CAAC;gBAC3E,CAAC,CAAC;aACH,CAAC,CACH,CAAC;QACJ,CAAC;IACH,CAAC;CACF;AA7CD,8DA6CC","sourcesContent":["import { awsNamingUtils } from 'quidproquo-actionprocessor-awslambda';\nimport { resolveAwsServiceAccountInfo } from 'quidproquo-config-aws';\nimport { ParameterQPQConfigSetting, QPQConfig } from 'quidproquo-core';\n\nimport { aws_iam, aws_ssm } from 'aws-cdk-lib';\nimport { Construct } from 'constructs';\n\nimport * as qpqDeployAwsCdkUtils from '../../../../utils';\nimport { QpqConstructBlock, QpqConstructBlockProps } from '../../../base/QpqConstructBlock';\nimport { QpqResource } from '../../../base/QpqResource';\n\nexport interface QpqCoreParameterConstructProps extends QpqConstructBlockProps {\n parameterConfig: ParameterQPQConfigSetting;\n}\n\nexport abstract class QpqCoreParameterConstructBase extends QpqConstructBlock {\n abstract stringParameter: aws_ssm.IStringParameter;\n\n public grantRead(grantee: aws_iam.IGrantable) {\n this.stringParameter.grantRead(grantee);\n }\n\n public grantWrite(grantee: aws_iam.IGrantable): void {\n this.stringParameter.grantWrite(grantee);\n }\n\n public grantAll(grantee: aws_iam.IGrantable): void {\n this.grantRead(grantee);\n this.grantWrite(grantee);\n }\n}\n\nexport class QpqCoreParameterConstruct extends QpqCoreParameterConstructBase {\n stringParameter: aws_ssm.IStringParameter;\n\n static fromOtherStack(scope: Construct, id: string, qpqConfig: QPQConfig, parameterConfig: ParameterQPQConfigSetting): QpqResource {\n const paramName = awsNamingUtils.resolveConfigRuntimeResourceNameFromConfig(parameterConfig.key, qpqConfig, parameterConfig.owner);\n\n class Import extends QpqCoreParameterConstructBase {\n stringParameter = aws_ssm.StringParameter.fromStringParameterName(scope, `${id}-${parameterConfig.uniqueKey}`, paramName);\n }\n\n return new Import(scope, id, { qpqConfig });\n }\n\n constructor(scope: Construct, id: string, props: QpqCoreParameterConstructProps) {\n super(scope, id, props);\n\n this.stringParameter = new aws_ssm.StringParameter(this, 'param', {\n parameterName: this.resourceName(props.parameterConfig.key),\n description: props.parameterConfig.key,\n stringValue: props.parameterConfig.value || 'Please set a value',\n\n // No additional costs ~ 4k max size\n tier: aws_ssm.ParameterTier.STANDARD,\n });\n\n qpqDeployAwsCdkUtils.applyEnvironmentTags(this.stringParameter, props.qpqConfig);\n }\n\n public static authorizeActionsForRole(role: aws_iam.IRole, parameterConfigs: ParameterQPQConfigSetting[], qpqConfig: QPQConfig) {\n if (parameterConfigs.length > 0) {\n role.addToPrincipalPolicy(\n new aws_iam.PolicyStatement({\n effect: aws_iam.Effect.ALLOW,\n actions: ['ssm:GetParameter', 'ssm:GetParameters', 'ssm:DescribeParameters'],\n resources: parameterConfigs.map((parameterConfig) => {\n const { awsRegion, awsAccountId } = resolveAwsServiceAccountInfo(qpqConfig, parameterConfig.owner);\n\n const paramName = awsNamingUtils.resolveConfigRuntimeResourceNameFromConfig(parameterConfig.key, qpqConfig, parameterConfig.owner);\n\n return `arn:aws:ssm:${awsRegion}:${awsAccountId}:parameter/${paramName}`;\n }),\n }),\n );\n }\n }\n}\n"]}
1
+ {"version":3,"file":"QpqCoreParameterConstruct.js","sourceRoot":"","sources":["../../../../../../src/constructs/feature/core/parameter/QpqCoreParameterConstruct.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+FAAsE;AACtE,iEAAqE;AAGrE,6CAA+C;AAG/C,wEAA0D;AAC1D,uEAA4F;AAO5F,MAAsB,6BAA8B,SAAQ,qCAAiB;IAGpE,SAAS,CAAC,OAA2B;QAC1C,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IAEM,UAAU,CAAC,OAA2B;QAC3C,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAC3C,CAAC;IAEM,QAAQ,CAAC,OAA2B;QACzC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;CACF;AAfD,sEAeC;AAED,MAAa,yBAA0B,SAAQ,6BAA6B;IAG1E,MAAM,CAAC,cAAc,CAAC,KAAgB,EAAE,EAAU,EAAE,SAAoB,EAAE,eAA0C;QAClH,MAAM,SAAS,GAAG,qDAAc,CAAC,0CAA0C,CAAC,eAAe,CAAC,GAAG,EAAE,SAAS,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC;QAEnI,MAAM,MAAO,SAAQ,6BAA6B;YAAlD;;gBACE,oBAAe,GAAG,qBAAO,CAAC,eAAe,CAAC,uBAAuB,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,eAAe,CAAC,SAAS,EAAE,EAAE,SAAS,CAAC,CAAC;YAC5H,CAAC;SAAA;QAED,OAAO,IAAI,MAAM,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,YAAY,KAAgB,EAAE,EAAU,EAAE,KAAqC;QAC7E,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;QAExB,IAAI,CAAC,eAAe,GAAG,IAAI,qBAAO,CAAC,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE;YAChE,aAAa,EAAE,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC;YAC3D,WAAW,EAAE,KAAK,CAAC,eAAe,CAAC,GAAG;YACtC,WAAW,EAAE,KAAK,CAAC,eAAe,CAAC,KAAK,IAAI,oBAAoB;YAEhE,oCAAoC;YACpC,IAAI,EAAE,qBAAO,CAAC,aAAa,CAAC,QAAQ;SACrC,CAAC,CAAC;QAEH,oBAAoB,CAAC,oBAAoB,CAAC,IAAI,CAAC,eAAe,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IACnF,CAAC;IAEM,MAAM,CAAC,uBAAuB,CAAC,KAAgB,EAAE,IAAmB,EAAE,gBAA6C,EAAE,SAAoB;QAC9I,MAAM,SAAS,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,eAAe,EAAE,EAAE;YACzD,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,IAAA,oDAA4B,EAAC,SAAS,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC;YAEnG,MAAM,SAAS,GAAG,qDAAc,CAAC,0CAA0C,CAAC,eAAe,CAAC,GAAG,EAAE,SAAS,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC;YAEnI,OAAO,eAAe,SAAS,IAAI,YAAY,cAAc,SAAS,EAAE,CAAC;QAC3E,CAAC,CAAC,CAAC;QAEH,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAEnC,wEAAwE;QACxE,oBAAoB,CAAC,6BAA6B,CAChD,KAAK,EACL,IAAI,EACJ,0BAA0B,EAC1B,CAAC,kBAAkB,EAAE,mBAAmB,EAAE,wBAAwB,CAAC,EACnE,SAAS,CACV,CAAC;IACJ,CAAC;CACF;AAhDD,8DAgDC","sourcesContent":["import { awsNamingUtils } from 'quidproquo-actionprocessor-awslambda';\nimport { resolveAwsServiceAccountInfo } from 'quidproquo-config-aws';\nimport { ParameterQPQConfigSetting, QPQConfig } from 'quidproquo-core';\n\nimport { aws_iam, aws_ssm } from 'aws-cdk-lib';\nimport { Construct } from 'constructs';\n\nimport * as qpqDeployAwsCdkUtils from '../../../../utils';\nimport { QpqConstructBlock, QpqConstructBlockProps } from '../../../base/QpqConstructBlock';\nimport { QpqResource } from '../../../base/QpqResource';\n\nexport interface QpqCoreParameterConstructProps extends QpqConstructBlockProps {\n parameterConfig: ParameterQPQConfigSetting;\n}\n\nexport abstract class QpqCoreParameterConstructBase extends QpqConstructBlock {\n abstract stringParameter: aws_ssm.IStringParameter;\n\n public grantRead(grantee: aws_iam.IGrantable) {\n this.stringParameter.grantRead(grantee);\n }\n\n public grantWrite(grantee: aws_iam.IGrantable): void {\n this.stringParameter.grantWrite(grantee);\n }\n\n public grantAll(grantee: aws_iam.IGrantable): void {\n this.grantRead(grantee);\n this.grantWrite(grantee);\n }\n}\n\nexport class QpqCoreParameterConstruct extends QpqCoreParameterConstructBase {\n stringParameter: aws_ssm.IStringParameter;\n\n static fromOtherStack(scope: Construct, id: string, qpqConfig: QPQConfig, parameterConfig: ParameterQPQConfigSetting): QpqResource {\n const paramName = awsNamingUtils.resolveConfigRuntimeResourceNameFromConfig(parameterConfig.key, qpqConfig, parameterConfig.owner);\n\n class Import extends QpqCoreParameterConstructBase {\n stringParameter = aws_ssm.StringParameter.fromStringParameterName(scope, `${id}-${parameterConfig.uniqueKey}`, paramName);\n }\n\n return new Import(scope, id, { qpqConfig });\n }\n\n constructor(scope: Construct, id: string, props: QpqCoreParameterConstructProps) {\n super(scope, id, props);\n\n this.stringParameter = new aws_ssm.StringParameter(this, 'param', {\n parameterName: this.resourceName(props.parameterConfig.key),\n description: props.parameterConfig.key,\n stringValue: props.parameterConfig.value || 'Please set a value',\n\n // No additional costs ~ 4k max size\n tier: aws_ssm.ParameterTier.STANDARD,\n });\n\n qpqDeployAwsCdkUtils.applyEnvironmentTags(this.stringParameter, props.qpqConfig);\n }\n\n public static authorizeActionsForRole(scope: Construct, role: aws_iam.IRole, parameterConfigs: ParameterQPQConfigSetting[], qpqConfig: QPQConfig) {\n const resources = parameterConfigs.map((parameterConfig) => {\n const { awsRegion, awsAccountId } = resolveAwsServiceAccountInfo(qpqConfig, parameterConfig.owner);\n\n const paramName = awsNamingUtils.resolveConfigRuntimeResourceNameFromConfig(parameterConfig.key, qpqConfig, parameterConfig.owner);\n\n return `arn:aws:ssm:${awsRegion}:${awsAccountId}:parameter/${paramName}`;\n });\n\n if (resources.length === 0) return;\n\n // Off the inline DefaultPolicy (10,240-byte cap) onto managed policies.\n qpqDeployAwsCdkUtils.attachManagedResourcePolicies(\n scope,\n role,\n 'webserverParameterAccess',\n ['ssm:GetParameter', 'ssm:GetParameters', 'ssm:DescribeParameters'],\n resources,\n );\n }\n}\n"]}
@@ -51,7 +51,10 @@ class QpqApiCoreQueueConstruct extends QpqConstructBlock_1.QpqConstructBlock {
51
51
  qpqConfig: props.qpqConfig,
52
52
  apiLayerVersions: props.apiLayerVersions,
53
53
  environment: {
54
- queueQPQConfigSetting: JSON.stringify(props.queueConfig),
54
+ // Just the name - the runtime resolves the full setting from the bundled
55
+ // qpqConfig. Serializing the whole setting here blows the lambda 4KB
56
+ // env limit once processors carry large globals (e.g. AI system prompts).
57
+ queueName: props.queueConfig.name,
55
58
  },
56
59
  reservedConcurrentExecutions: props.queueConfig.maxConcurrentExecutions,
57
60
  // Timeout in 15 mins ~ Max
@@ -1 +1 @@
1
- {"version":3,"file":"QpqApiCoreQueueConstruct.js","sourceRoot":"","sources":["../../../../../../src/constructs/feature/core/queue/QpqApiCoreQueueConstruct.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qDAAsE;AAEtE,6CAA0F;AAC1F,iDAAmC;AAGnC,uEAA4F;AAC5F,sDAAmD;AACnD,mFAAgF;AAChF,mEAAgE;AAOhE,MAAa,wBAAyB,SAAQ,qCAAiB;IAC7D,YAAY,KAAgB,EAAE,EAAU,EAAE,KAAoC;QAC5E,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;QAExB,MAAM,aAAa,GAAG,IAAI,mBAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,WAAW,CAAC,SAAS,EAAE;YACpE,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC,SAAS,QAAQ,CAAC;YACvE,YAAY,EAAE,qBAAqB;YACnC,YAAY,EAAE,qBAAqB;YAEnC,SAAS,EAAE,KAAK,CAAC,SAAS;YAE1B,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;YAExC,WAAW,EAAE;gBACX,qBAAqB,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,WAAW,CAAC;aACzD;YAED,4BAA4B,EAAE,KAAK,CAAC,WAAW,CAAC,uBAAuB;YAEvE,2BAA2B;YAC3B,qFAAqF;YACrF,qFAAqF;YACrF,0FAA0F;YAC1F,qFAAqF;YACrF,6FAA6F;YAC7F,gBAAgB,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,gBAAgB,EAAE,EAAE,GAAG,EAAE,CAAC;YAEvE,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE;SAC5B,CAAC,CAAC;QAEH,MAAM,aAAa,GAAG,6CAAqB,CAAC,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;QAE9G,uFAAuF;QACvF,8BAAY,CAAC,4CAA4C,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAE3E,KAAK,CAAC,WAAW,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,oBAAoB,EAAE,EAAE;YACvE,MAAM,QAAQ,GAAG,mDAAwB,CAAC,cAAc,CAAC,IAAI,EAAE,aAAa,oBAAoB,EAAE,EAAE,KAAK,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;YAE3I,QAAQ,CAAC,KAAK,CAAC,eAAe,CAC5B,IAAI,mCAAqB,CAAC,eAAe,CAAC,aAAa,CAAC,KAAK,EAAE;gBAC7D,kBAAkB,EAAE,IAAI;gBAExB,yBAAyB;gBACzB,kBAAkB;gBAClB,oDAAoD;gBACpD,iFAAiF;gBACjF,0CAA0C;gBAC1C,SAAS;gBACT,QAAQ;gBACR,KAAK;aACN,CAAC,CACH,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,MAAM,kBAAkB;YACtB,kFAAkF;YAClF,+EAA+E;YAC/E,uBAAuB,EAAE,IAAI,IAE1B,CAAC,KAAK,CAAC,WAAW,CAAC,SAAS,GAAG,CAAC;YACjC,CAAC,iBACG,SAAS,EAAE,KAAK,CAAC,WAAW,CAAC,SAAS,IAGnC,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,oBAAoB,CAAC,EAAE,CAAC,EAE5H,CAAC,CAAC,EAAE,CAAC,CACR,CAAC;QAEF,aAAa,CAAC,cAAc,CAAC,cAAc,CAAC,IAAI,sCAAwB,CAAC,cAAc,CAAC,aAAa,CAAC,KAAK,EAAE,kBAAkB,CAAC,CAAC,CAAC;IACpI,CAAC;CACF;AAvED,4DAuEC","sourcesContent":["import { qpqCoreUtils, QueueQPQConfigSetting } from 'quidproquo-core';\n\nimport { aws_lambda, aws_lambda_event_sources, aws_sns_subscriptions } from 'aws-cdk-lib';\nimport * as cdk from 'aws-cdk-lib';\nimport { Construct } from 'constructs';\n\nimport { QpqConstructBlock, QpqConstructBlockProps } from '../../../base/QpqConstructBlock';\nimport { Function } from '../../../basic/Function';\nimport { QpqCoreEventBusConstruct } from '../eventBus/QpqCoreEventBusConstruct';\nimport { QpqCoreQueueConstruct } from './QpqCoreQueueConstruct';\n\nexport interface QpqApiCoreQueueConstructProps extends QpqConstructBlockProps {\n queueConfig: QueueQPQConfigSetting;\n apiLayerVersions?: aws_lambda.ILayerVersion[];\n}\n\nexport class QpqApiCoreQueueConstruct extends QpqConstructBlock {\n constructor(scope: Construct, id: string, props: QpqApiCoreQueueConstructProps) {\n super(scope, id, props);\n\n const queueFunction = new Function(this, props.queueConfig.uniqueKey, {\n functionName: this.resourceName(`${props.queueConfig.uniqueKey}-queue`),\n functionType: 'sqsEvent_queueEvent',\n executorName: 'sqsEvent_queueEvent',\n\n qpqConfig: props.qpqConfig,\n\n apiLayerVersions: props.apiLayerVersions,\n\n environment: {\n queueQPQConfigSetting: JSON.stringify(props.queueConfig),\n },\n\n reservedConcurrentExecutions: props.queueConfig.maxConcurrentExecutions,\n\n // Timeout in 15 mins ~ Max\n // Note: AWS requires that the visibility timeout of the SQS queue be greater than or\n // equal to the timeout of the Lambda function. This is because if a message is\n // processed by a Lambda function for a time longer than the SQS visibility timeout,\n // the message will become visible in the SQS queue again and could be consumed\n // by another Lambda function, resulting in the message being processed multiple times.\n timeoutInSeconds: Math.min(props.queueConfig.ttRetryInSeconds, 15 * 60),\n\n role: this.getServiceRole(),\n });\n\n const queueResource = QpqCoreQueueConstruct.fromOtherStack(this, 'queue', props.qpqConfig, props.queueConfig);\n\n // Fails synth when a FIFO queue subscribes to a standard bus (AWS can't deliver those)\n qpqCoreUtils.assertFifoQueueEventBusSubscriptionsAreValid(props.qpqConfig);\n\n props.queueConfig.eventBusSubscriptions.forEach((eventBusSubscription) => {\n const eventBus = QpqCoreEventBusConstruct.fromOtherStack(this, `event-bus-${eventBusSubscription}`, props.qpqConfig, eventBusSubscription);\n\n eventBus.topic.addSubscription(\n new aws_sns_subscriptions.SqsSubscription(queueResource.queue, {\n rawMessageDelivery: true,\n\n // No wildcard support :(\n // filterPolicy: {\n // type: aws_sns.SubscriptionFilter.stringFilter({\n // allowlist: Object.keys(props.queueConfig.qpqQueueProcessors).map((type) =>\n // type.replaceAll(/{(.+?)}/g, '*'),\n // ),\n // }),\n // },\n }),\n );\n });\n\n const eventSourceOptions: aws_lambda_event_sources.SqsEventSourceProps = {\n // Honour the batchItemFailures the runtime returns - without this, SQS treats the\n // whole batch as successful and failed messages are deleted instead of retried\n reportBatchItemFailures: true,\n\n ...(props.queueConfig.batchSize > 0\n ? {\n batchSize: props.queueConfig.batchSize,\n\n // FIFO event sources don't support a batching window\n ...(props.queueConfig.isFifo ? {} : { maxBatchingWindow: cdk.Duration.seconds(props.queueConfig.batchWindowInSeconds) }),\n }\n : {}),\n };\n\n queueFunction.lambdaFunction.addEventSource(new aws_lambda_event_sources.SqsEventSource(queueResource.queue, eventSourceOptions));\n }\n}\n"]}
1
+ {"version":3,"file":"QpqApiCoreQueueConstruct.js","sourceRoot":"","sources":["../../../../../../src/constructs/feature/core/queue/QpqApiCoreQueueConstruct.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qDAAsE;AAEtE,6CAA0F;AAC1F,iDAAmC;AAGnC,uEAA4F;AAC5F,sDAAmD;AACnD,mFAAgF;AAChF,mEAAgE;AAOhE,MAAa,wBAAyB,SAAQ,qCAAiB;IAC7D,YAAY,KAAgB,EAAE,EAAU,EAAE,KAAoC;QAC5E,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;QAExB,MAAM,aAAa,GAAG,IAAI,mBAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,WAAW,CAAC,SAAS,EAAE;YACpE,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC,SAAS,QAAQ,CAAC;YACvE,YAAY,EAAE,qBAAqB;YACnC,YAAY,EAAE,qBAAqB;YAEnC,SAAS,EAAE,KAAK,CAAC,SAAS;YAE1B,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;YAExC,WAAW,EAAE;gBACX,yEAAyE;gBACzE,qEAAqE;gBACrE,0EAA0E;gBAC1E,SAAS,EAAE,KAAK,CAAC,WAAW,CAAC,IAAI;aAClC;YAED,4BAA4B,EAAE,KAAK,CAAC,WAAW,CAAC,uBAAuB;YAEvE,2BAA2B;YAC3B,qFAAqF;YACrF,qFAAqF;YACrF,0FAA0F;YAC1F,qFAAqF;YACrF,6FAA6F;YAC7F,gBAAgB,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,gBAAgB,EAAE,EAAE,GAAG,EAAE,CAAC;YAEvE,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE;SAC5B,CAAC,CAAC;QAEH,MAAM,aAAa,GAAG,6CAAqB,CAAC,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;QAE9G,uFAAuF;QACvF,8BAAY,CAAC,4CAA4C,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAE3E,KAAK,CAAC,WAAW,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,oBAAoB,EAAE,EAAE;YACvE,MAAM,QAAQ,GAAG,mDAAwB,CAAC,cAAc,CAAC,IAAI,EAAE,aAAa,oBAAoB,EAAE,EAAE,KAAK,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;YAE3I,QAAQ,CAAC,KAAK,CAAC,eAAe,CAC5B,IAAI,mCAAqB,CAAC,eAAe,CAAC,aAAa,CAAC,KAAK,EAAE;gBAC7D,kBAAkB,EAAE,IAAI;gBAExB,yBAAyB;gBACzB,kBAAkB;gBAClB,oDAAoD;gBACpD,iFAAiF;gBACjF,0CAA0C;gBAC1C,SAAS;gBACT,QAAQ;gBACR,KAAK;aACN,CAAC,CACH,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,MAAM,kBAAkB;YACtB,kFAAkF;YAClF,+EAA+E;YAC/E,uBAAuB,EAAE,IAAI,IAE1B,CAAC,KAAK,CAAC,WAAW,CAAC,SAAS,GAAG,CAAC;YACjC,CAAC,iBACG,SAAS,EAAE,KAAK,CAAC,WAAW,CAAC,SAAS,IAGnC,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,oBAAoB,CAAC,EAAE,CAAC,EAE5H,CAAC,CAAC,EAAE,CAAC,CACR,CAAC;QAEF,aAAa,CAAC,cAAc,CAAC,cAAc,CAAC,IAAI,sCAAwB,CAAC,cAAc,CAAC,aAAa,CAAC,KAAK,EAAE,kBAAkB,CAAC,CAAC,CAAC;IACpI,CAAC;CACF;AA1ED,4DA0EC","sourcesContent":["import { qpqCoreUtils, QueueQPQConfigSetting } from 'quidproquo-core';\n\nimport { aws_lambda, aws_lambda_event_sources, aws_sns_subscriptions } from 'aws-cdk-lib';\nimport * as cdk from 'aws-cdk-lib';\nimport { Construct } from 'constructs';\n\nimport { QpqConstructBlock, QpqConstructBlockProps } from '../../../base/QpqConstructBlock';\nimport { Function } from '../../../basic/Function';\nimport { QpqCoreEventBusConstruct } from '../eventBus/QpqCoreEventBusConstruct';\nimport { QpqCoreQueueConstruct } from './QpqCoreQueueConstruct';\n\nexport interface QpqApiCoreQueueConstructProps extends QpqConstructBlockProps {\n queueConfig: QueueQPQConfigSetting;\n apiLayerVersions?: aws_lambda.ILayerVersion[];\n}\n\nexport class QpqApiCoreQueueConstruct extends QpqConstructBlock {\n constructor(scope: Construct, id: string, props: QpqApiCoreQueueConstructProps) {\n super(scope, id, props);\n\n const queueFunction = new Function(this, props.queueConfig.uniqueKey, {\n functionName: this.resourceName(`${props.queueConfig.uniqueKey}-queue`),\n functionType: 'sqsEvent_queueEvent',\n executorName: 'sqsEvent_queueEvent',\n\n qpqConfig: props.qpqConfig,\n\n apiLayerVersions: props.apiLayerVersions,\n\n environment: {\n // Just the name - the runtime resolves the full setting from the bundled\n // qpqConfig. Serializing the whole setting here blows the lambda 4KB\n // env limit once processors carry large globals (e.g. AI system prompts).\n queueName: props.queueConfig.name,\n },\n\n reservedConcurrentExecutions: props.queueConfig.maxConcurrentExecutions,\n\n // Timeout in 15 mins ~ Max\n // Note: AWS requires that the visibility timeout of the SQS queue be greater than or\n // equal to the timeout of the Lambda function. This is because if a message is\n // processed by a Lambda function for a time longer than the SQS visibility timeout,\n // the message will become visible in the SQS queue again and could be consumed\n // by another Lambda function, resulting in the message being processed multiple times.\n timeoutInSeconds: Math.min(props.queueConfig.ttRetryInSeconds, 15 * 60),\n\n role: this.getServiceRole(),\n });\n\n const queueResource = QpqCoreQueueConstruct.fromOtherStack(this, 'queue', props.qpqConfig, props.queueConfig);\n\n // Fails synth when a FIFO queue subscribes to a standard bus (AWS can't deliver those)\n qpqCoreUtils.assertFifoQueueEventBusSubscriptionsAreValid(props.qpqConfig);\n\n props.queueConfig.eventBusSubscriptions.forEach((eventBusSubscription) => {\n const eventBus = QpqCoreEventBusConstruct.fromOtherStack(this, `event-bus-${eventBusSubscription}`, props.qpqConfig, eventBusSubscription);\n\n eventBus.topic.addSubscription(\n new aws_sns_subscriptions.SqsSubscription(queueResource.queue, {\n rawMessageDelivery: true,\n\n // No wildcard support :(\n // filterPolicy: {\n // type: aws_sns.SubscriptionFilter.stringFilter({\n // allowlist: Object.keys(props.queueConfig.qpqQueueProcessors).map((type) =>\n // type.replaceAll(/{(.+?)}/g, '*'),\n // ),\n // }),\n // },\n }),\n );\n });\n\n const eventSourceOptions: aws_lambda_event_sources.SqsEventSourceProps = {\n // Honour the batchItemFailures the runtime returns - without this, SQS treats the\n // whole batch as successful and failed messages are deleted instead of retried\n reportBatchItemFailures: true,\n\n ...(props.queueConfig.batchSize > 0\n ? {\n batchSize: props.queueConfig.batchSize,\n\n // FIFO event sources don't support a batching window\n ...(props.queueConfig.isFifo ? {} : { maxBatchingWindow: cdk.Duration.seconds(props.queueConfig.batchWindowInSeconds) }),\n }\n : {}),\n };\n\n queueFunction.lambdaFunction.addEventSource(new aws_lambda_event_sources.SqsEventSource(queueResource.queue, eventSourceOptions));\n }\n}\n"]}
@@ -16,5 +16,5 @@ export declare class QpqCoreSecretConstruct extends QpqCoreSecretConstructBase {
16
16
  secret: aws_secretsmanager.ISecret;
17
17
  static fromOtherStack(scope: Construct, id: string, qpqConfig: QPQConfig, secretConfig: SecretQPQConfigSetting): QpqResource;
18
18
  constructor(scope: Construct, id: string, props: QpqCoreSecretConstructProps);
19
- static authorizeActionsForRole(role: aws_iam.IRole, secretConfigs: SecretQPQConfigSetting[], qpqConfig: QPQConfig): void;
19
+ static authorizeActionsForRole(scope: Construct, role: aws_iam.IRole, secretConfigs: SecretQPQConfigSetting[], qpqConfig: QPQConfig): void;
20
20
  }
@@ -73,18 +73,16 @@ class QpqCoreSecretConstruct extends QpqCoreSecretConstructBase {
73
73
  });
74
74
  qpqDeployAwsCdkUtils.applyEnvironmentTags(this.secret, props.qpqConfig);
75
75
  }
76
- static authorizeActionsForRole(role, secretConfigs, qpqConfig) {
77
- if (secretConfigs.length > 0) {
78
- role.addToPrincipalPolicy(new aws_cdk_lib_1.aws_iam.PolicyStatement({
79
- effect: aws_cdk_lib_1.aws_iam.Effect.ALLOW,
80
- actions: ['secretsmanager:GetSecretValue'],
81
- resources: secretConfigs.map((secretConfig) => {
82
- const { awsRegion, awsAccountId } = (0, quidproquo_config_aws_1.resolveAwsServiceAccountInfo)(qpqConfig, secretConfig.owner);
83
- const secretName = quidproquo_actionprocessor_awslambda_1.awsNamingUtils.resolveConfigRuntimeResourceNameFromConfig(secretConfig.key, qpqConfig, secretConfig.owner);
84
- return `arn:aws:secretsmanager:${awsRegion}:${awsAccountId}:secret:${secretName}-*`;
85
- }),
86
- }));
87
- }
76
+ static authorizeActionsForRole(scope, role, secretConfigs, qpqConfig) {
77
+ const resources = secretConfigs.map((secretConfig) => {
78
+ const { awsRegion, awsAccountId } = (0, quidproquo_config_aws_1.resolveAwsServiceAccountInfo)(qpqConfig, secretConfig.owner);
79
+ const secretName = quidproquo_actionprocessor_awslambda_1.awsNamingUtils.resolveConfigRuntimeResourceNameFromConfig(secretConfig.key, qpqConfig, secretConfig.owner);
80
+ return `arn:aws:secretsmanager:${awsRegion}:${awsAccountId}:secret:${secretName}-*`;
81
+ });
82
+ if (resources.length === 0)
83
+ return;
84
+ // Off the inline DefaultPolicy (10,240-byte cap) onto managed policies.
85
+ qpqDeployAwsCdkUtils.attachManagedResourcePolicies(scope, role, 'webserverSecretAccess', ['secretsmanager:GetSecretValue'], resources);
88
86
  }
89
87
  }
90
88
  exports.QpqCoreSecretConstruct = QpqCoreSecretConstruct;
@@ -1 +1 @@
1
- {"version":3,"file":"QpqCoreSecretConstruct.js","sourceRoot":"","sources":["../../../../../../src/constructs/feature/core/secret/QpqCoreSecretConstruct.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+FAAsE;AACtE,iEAAqE;AAGrE,6CAA0D;AAC1D,iDAAmC;AAGnC,wEAA0D;AAC1D,uEAA4F;AAO5F,MAAsB,0BAA2B,SAAQ,qCAAiB;IAGjE,SAAS,CAAC,OAA2B;QAC1C,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACxC,CAAC;IAEM,UAAU,CAAC,OAA2B;QAC3C,OAAO,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC;IAEM,QAAQ,CAAC,OAA2B;QACzC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;CACF;AAfD,gEAeC;AAED,MAAa,sBAAuB,SAAQ,0BAA0B;IAGpE,MAAM,CAAC,cAAc,CAAC,KAAgB,EAAE,EAAU,EAAE,SAAoB,EAAE,YAAoC;QAC5G,MAAM,UAAU,GAAG,qDAAc,CAAC,0CAA0C,CAAC,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QAE9H,MAAM,MAAO,SAAQ,0BAA0B;YAA/C;;gBACE,WAAM,GAAG,gCAAkB,CAAC,MAAM,CAAC,gBAAgB,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,YAAY,CAAC,SAAS,EAAE,EAAE,UAAU,CAAC,CAAC;YAC5G,CAAC;SAAA;QAED,OAAO,IAAI,MAAM,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,YAAY,KAAgB,EAAE,EAAU,EAAE,KAAkC;QAC1E,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;QAExB,IAAI,CAAC,MAAM,GAAG,IAAI,gCAAkB,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE;YAC1D,UAAU,EAAE,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC;YACrD,aAAa,EAAE,GAAG,CAAC,aAAa,CAAC,OAAO;YACxC,WAAW,EAAE,KAAK,CAAC,YAAY,CAAC,GAAG;SACpC,CAAC,CAAC;QAEH,oBAAoB,CAAC,oBAAoB,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAC1E,CAAC;IAEM,MAAM,CAAC,uBAAuB,CAAC,IAAmB,EAAE,aAAuC,EAAE,SAAoB;QACtH,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,IAAI,CAAC,oBAAoB,CACvB,IAAI,qBAAO,CAAC,eAAe,CAAC;gBAC1B,MAAM,EAAE,qBAAO,CAAC,MAAM,CAAC,KAAK;gBAC5B,OAAO,EAAE,CAAC,+BAA+B,CAAC;gBAC1C,SAAS,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,YAAY,EAAE,EAAE;oBAC5C,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,IAAA,oDAA4B,EAAC,SAAS,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;oBAEhG,MAAM,UAAU,GAAG,qDAAc,CAAC,0CAA0C,CAAC,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;oBAE9H,OAAO,0BAA0B,SAAS,IAAI,YAAY,WAAW,UAAU,IAAI,CAAC;gBACtF,CAAC,CAAC;aACH,CAAC,CACH,CAAC;QACJ,CAAC;IACH,CAAC;CACF;AA1CD,wDA0CC","sourcesContent":["import { awsNamingUtils } from 'quidproquo-actionprocessor-awslambda';\nimport { resolveAwsServiceAccountInfo } from 'quidproquo-config-aws';\nimport { QPQConfig, SecretQPQConfigSetting } from 'quidproquo-core';\n\nimport { aws_iam, aws_secretsmanager } from 'aws-cdk-lib';\nimport * as cdk from 'aws-cdk-lib';\nimport { Construct } from 'constructs';\n\nimport * as qpqDeployAwsCdkUtils from '../../../../utils';\nimport { QpqConstructBlock, QpqConstructBlockProps } from '../../../base/QpqConstructBlock';\nimport { QpqResource } from '../../../base/QpqResource';\n\nexport interface QpqCoreSecretConstructProps extends QpqConstructBlockProps {\n secretConfig: SecretQPQConfigSetting;\n}\n\nexport abstract class QpqCoreSecretConstructBase extends QpqConstructBlock implements QpqResource {\n abstract secret: aws_secretsmanager.ISecret;\n\n public grantRead(grantee: aws_iam.IGrantable): aws_iam.Grant {\n return this.secret.grantRead(grantee);\n }\n\n public grantWrite(grantee: aws_iam.IGrantable): aws_iam.Grant {\n return this.secret.grantWrite(grantee);\n }\n\n public grantAll(grantee: aws_iam.IGrantable): void {\n this.grantRead(grantee);\n this.grantWrite(grantee);\n }\n}\n\nexport class QpqCoreSecretConstruct extends QpqCoreSecretConstructBase {\n secret: aws_secretsmanager.ISecret;\n\n static fromOtherStack(scope: Construct, id: string, qpqConfig: QPQConfig, secretConfig: SecretQPQConfigSetting): QpqResource {\n const secretName = awsNamingUtils.resolveConfigRuntimeResourceNameFromConfig(secretConfig.key, qpqConfig, secretConfig.owner);\n\n class Import extends QpqCoreSecretConstructBase {\n secret = aws_secretsmanager.Secret.fromSecretNameV2(scope, `${id}-${secretConfig.uniqueKey}`, secretName);\n }\n\n return new Import(scope, id, { qpqConfig });\n }\n\n constructor(scope: Construct, id: string, props: QpqCoreSecretConstructProps) {\n super(scope, id, props);\n\n this.secret = new aws_secretsmanager.Secret(this, 'secret', {\n secretName: this.resourceName(props.secretConfig.key),\n removalPolicy: cdk.RemovalPolicy.DESTROY,\n description: props.secretConfig.key,\n });\n\n qpqDeployAwsCdkUtils.applyEnvironmentTags(this.secret, props.qpqConfig);\n }\n\n public static authorizeActionsForRole(role: aws_iam.IRole, secretConfigs: SecretQPQConfigSetting[], qpqConfig: QPQConfig) {\n if (secretConfigs.length > 0) {\n role.addToPrincipalPolicy(\n new aws_iam.PolicyStatement({\n effect: aws_iam.Effect.ALLOW,\n actions: ['secretsmanager:GetSecretValue'],\n resources: secretConfigs.map((secretConfig) => {\n const { awsRegion, awsAccountId } = resolveAwsServiceAccountInfo(qpqConfig, secretConfig.owner);\n\n const secretName = awsNamingUtils.resolveConfigRuntimeResourceNameFromConfig(secretConfig.key, qpqConfig, secretConfig.owner);\n\n return `arn:aws:secretsmanager:${awsRegion}:${awsAccountId}:secret:${secretName}-*`;\n }),\n }),\n );\n }\n }\n}\n"]}
1
+ {"version":3,"file":"QpqCoreSecretConstruct.js","sourceRoot":"","sources":["../../../../../../src/constructs/feature/core/secret/QpqCoreSecretConstruct.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+FAAsE;AACtE,iEAAqE;AAGrE,6CAA0D;AAC1D,iDAAmC;AAGnC,wEAA0D;AAC1D,uEAA4F;AAO5F,MAAsB,0BAA2B,SAAQ,qCAAiB;IAGjE,SAAS,CAAC,OAA2B;QAC1C,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACxC,CAAC;IAEM,UAAU,CAAC,OAA2B;QAC3C,OAAO,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC;IAEM,QAAQ,CAAC,OAA2B;QACzC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;CACF;AAfD,gEAeC;AAED,MAAa,sBAAuB,SAAQ,0BAA0B;IAGpE,MAAM,CAAC,cAAc,CAAC,KAAgB,EAAE,EAAU,EAAE,SAAoB,EAAE,YAAoC;QAC5G,MAAM,UAAU,GAAG,qDAAc,CAAC,0CAA0C,CAAC,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QAE9H,MAAM,MAAO,SAAQ,0BAA0B;YAA/C;;gBACE,WAAM,GAAG,gCAAkB,CAAC,MAAM,CAAC,gBAAgB,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,YAAY,CAAC,SAAS,EAAE,EAAE,UAAU,CAAC,CAAC;YAC5G,CAAC;SAAA;QAED,OAAO,IAAI,MAAM,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,YAAY,KAAgB,EAAE,EAAU,EAAE,KAAkC;QAC1E,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;QAExB,IAAI,CAAC,MAAM,GAAG,IAAI,gCAAkB,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE;YAC1D,UAAU,EAAE,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC;YACrD,aAAa,EAAE,GAAG,CAAC,aAAa,CAAC,OAAO;YACxC,WAAW,EAAE,KAAK,CAAC,YAAY,CAAC,GAAG;SACpC,CAAC,CAAC;QAEH,oBAAoB,CAAC,oBAAoB,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAC1E,CAAC;IAEM,MAAM,CAAC,uBAAuB,CAAC,KAAgB,EAAE,IAAmB,EAAE,aAAuC,EAAE,SAAoB;QACxI,MAAM,SAAS,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,YAAY,EAAE,EAAE;YACnD,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,IAAA,oDAA4B,EAAC,SAAS,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;YAEhG,MAAM,UAAU,GAAG,qDAAc,CAAC,0CAA0C,CAAC,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;YAE9H,OAAO,0BAA0B,SAAS,IAAI,YAAY,WAAW,UAAU,IAAI,CAAC;QACtF,CAAC,CAAC,CAAC;QAEH,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAEnC,wEAAwE;QACxE,oBAAoB,CAAC,6BAA6B,CAChD,KAAK,EACL,IAAI,EACJ,uBAAuB,EACvB,CAAC,+BAA+B,CAAC,EACjC,SAAS,CACV,CAAC;IACJ,CAAC;CACF;AA7CD,wDA6CC","sourcesContent":["import { awsNamingUtils } from 'quidproquo-actionprocessor-awslambda';\nimport { resolveAwsServiceAccountInfo } from 'quidproquo-config-aws';\nimport { QPQConfig, SecretQPQConfigSetting } from 'quidproquo-core';\n\nimport { aws_iam, aws_secretsmanager } from 'aws-cdk-lib';\nimport * as cdk from 'aws-cdk-lib';\nimport { Construct } from 'constructs';\n\nimport * as qpqDeployAwsCdkUtils from '../../../../utils';\nimport { QpqConstructBlock, QpqConstructBlockProps } from '../../../base/QpqConstructBlock';\nimport { QpqResource } from '../../../base/QpqResource';\n\nexport interface QpqCoreSecretConstructProps extends QpqConstructBlockProps {\n secretConfig: SecretQPQConfigSetting;\n}\n\nexport abstract class QpqCoreSecretConstructBase extends QpqConstructBlock implements QpqResource {\n abstract secret: aws_secretsmanager.ISecret;\n\n public grantRead(grantee: aws_iam.IGrantable): aws_iam.Grant {\n return this.secret.grantRead(grantee);\n }\n\n public grantWrite(grantee: aws_iam.IGrantable): aws_iam.Grant {\n return this.secret.grantWrite(grantee);\n }\n\n public grantAll(grantee: aws_iam.IGrantable): void {\n this.grantRead(grantee);\n this.grantWrite(grantee);\n }\n}\n\nexport class QpqCoreSecretConstruct extends QpqCoreSecretConstructBase {\n secret: aws_secretsmanager.ISecret;\n\n static fromOtherStack(scope: Construct, id: string, qpqConfig: QPQConfig, secretConfig: SecretQPQConfigSetting): QpqResource {\n const secretName = awsNamingUtils.resolveConfigRuntimeResourceNameFromConfig(secretConfig.key, qpqConfig, secretConfig.owner);\n\n class Import extends QpqCoreSecretConstructBase {\n secret = aws_secretsmanager.Secret.fromSecretNameV2(scope, `${id}-${secretConfig.uniqueKey}`, secretName);\n }\n\n return new Import(scope, id, { qpqConfig });\n }\n\n constructor(scope: Construct, id: string, props: QpqCoreSecretConstructProps) {\n super(scope, id, props);\n\n this.secret = new aws_secretsmanager.Secret(this, 'secret', {\n secretName: this.resourceName(props.secretConfig.key),\n removalPolicy: cdk.RemovalPolicy.DESTROY,\n description: props.secretConfig.key,\n });\n\n qpqDeployAwsCdkUtils.applyEnvironmentTags(this.secret, props.qpqConfig);\n }\n\n public static authorizeActionsForRole(scope: Construct, role: aws_iam.IRole, secretConfigs: SecretQPQConfigSetting[], qpqConfig: QPQConfig) {\n const resources = secretConfigs.map((secretConfig) => {\n const { awsRegion, awsAccountId } = resolveAwsServiceAccountInfo(qpqConfig, secretConfig.owner);\n\n const secretName = awsNamingUtils.resolveConfigRuntimeResourceNameFromConfig(secretConfig.key, qpqConfig, secretConfig.owner);\n\n return `arn:aws:secretsmanager:${awsRegion}:${awsAccountId}:secret:${secretName}-*`;\n });\n\n if (resources.length === 0) return;\n\n // Off the inline DefaultPolicy (10,240-byte cap) onto managed policies.\n qpqDeployAwsCdkUtils.attachManagedResourcePolicies(\n scope,\n role,\n 'webserverSecretAccess',\n ['secretsmanager:GetSecretValue'],\n resources,\n );\n }\n}\n"]}
@@ -28,5 +28,5 @@ export declare class QpqCoreStorageDriveConstruct extends QpqCoreStorageDriveCon
28
28
  bucket: aws_s3.IBucket;
29
29
  static fromOtherStack(scope: Construct, id: string, qpqConfig: QPQConfig, storageDriveConfig: StorageDriveQPQConfigSetting): QpqCoreStorageDriveConstructBase;
30
30
  constructor(scope: Construct, id: string, props: QpqCoreStorageDriveConstructProps);
31
- static authorizeActionsForRole(role: aws_iam.IRole, qpqConfig: QPQConfig, ownedStorageDrives: QpqCoreStorageDriveConstruct[]): void;
31
+ static authorizeActionsForRole(scope: Construct, role: aws_iam.IRole, qpqConfig: QPQConfig, ownedStorageDrives: QpqCoreStorageDriveConstruct[]): void;
32
32
  }
@@ -158,7 +158,7 @@ class QpqCoreStorageDriveConstruct extends QpqCoreStorageDriveConstructBase {
158
158
  });
159
159
  }
160
160
  }
161
- static authorizeActionsForRole(role, qpqConfig, ownedStorageDrives) {
161
+ static authorizeActionsForRole(scope, role, qpqConfig, ownedStorageDrives) {
162
162
  // CDK-known ARNs for drives created in this stack.
163
163
  const ownedArns = ownedStorageDrives.flatMap((sd) => [sd.bucket.bucketArn, sd.bucket.arnForObjects('*')]);
164
164
  // Deterministically-computed ARNs for drives declared in this service's
@@ -176,11 +176,9 @@ class QpqCoreStorageDriveConstruct extends QpqCoreStorageDriveConstructBase {
176
176
  const resources = [...ownedArns, ...foreignArns];
177
177
  if (resources.length === 0)
178
178
  return;
179
- role.addToPrincipalPolicy(new aws_cdk_lib_1.aws_iam.PolicyStatement({
180
- effect: aws_cdk_lib_1.aws_iam.Effect.ALLOW,
181
- actions: ['s3:GetObject', 's3:PutObject', 's3:DeleteObject', 's3:ListBucket'],
182
- resources,
183
- }));
179
+ // Off the inline DefaultPolicy (10,240-byte cap) onto managed policies — the
180
+ // drive ARN list grows with every eventDoc collection's asset bucket.
181
+ qpqDeployAwsCdkUtils.attachManagedResourcePolicies(scope, role, 'webserverStorageDriveAccess', ['s3:GetObject', 's3:PutObject', 's3:DeleteObject', 's3:ListBucket'], resources);
184
182
  // Grant KMS permissions for any encrypted drives (owned or foreign) whose
185
183
  // customer-managed key is declared in this service's config.
186
184
  const kmsArns = [...ownedDriveConfigs, ...foreignDriveConfigs]
@@ -1 +1 @@
1
- {"version":3,"file":"QpqCoreStorageDriveConstruct.js","sourceRoot":"","sources":["../../../../../../src/constructs/feature/core/storageDrive/QpqCoreStorageDriveConstruct.ts"],"names":[],"mappings":"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","sourcesContent":["import { awsNamingUtils } from 'quidproquo-actionprocessor-awslambda';\nimport { AwsDataStoreRemovalPolicy, qpqConfigAwsUtils } from 'quidproquo-config-aws';\nimport { QPQConfig, qpqCoreUtils, StorageDriveLifecycleRule, StorageDriveQPQConfigSetting, StorageDriveTransition } from 'quidproquo-core';\n\nimport { aws_iam, aws_kms, aws_s3, aws_s3_deployment } from 'aws-cdk-lib';\nimport * as cdk from 'aws-cdk-lib';\nimport { Construct } from 'constructs';\n\nimport { qpqAwsCdkPathUtils } from '../../../../utils';\nimport * as qpqDeployAwsCdkUtils from '../../../../utils/qpqDeployAwsCdkUtils';\nimport { QpqConstructBlock, QpqConstructBlockProps } from '../../../base/QpqConstructBlock';\nimport { QpqResource } from '../../../base/QpqResource';\nexport interface QpqCoreStorageDriveConstructProps extends QpqConstructBlockProps {\n storageDriveConfig: StorageDriveQPQConfigSetting;\n\n /**\n * Resolved browser origins for the bucket's CORS policy. Computed by the\n * (web-aware) caller so this core construct stays domain-agnostic. Defaults\n * to '*' when omitted (headless/core-only deployments have no browser origin).\n */\n corsAllowedOrigins?: string[];\n\n /**\n * Whether this drive's bucket is served through a CloudFront distribution\n * (resolved by the web-aware caller from web entry configs). Only then does\n * the bucket policy grant CloudFront read access.\n */\n allowCloudFrontRead?: boolean;\n}\n\nexport abstract class QpqCoreStorageDriveConstructBase extends QpqConstructBlock implements QpqResource {\n abstract bucket: aws_s3.IBucket;\n\n public grantRead(grantee: aws_iam.IGrantable): aws_iam.Grant {\n return this.bucket.grantRead(grantee);\n }\n\n public grantWrite(grantee: aws_iam.IGrantable): aws_iam.Grant {\n return this.bucket.grantWrite(grantee);\n }\n\n public grantAll(grantee: aws_iam.IGrantable): void {\n this.grantRead(grantee);\n this.grantWrite(grantee);\n }\n}\n\nconst convertStorageDriveTransitionToAwsS3Transition = (storageDriveTransition: StorageDriveTransition): aws_s3.Transition => ({\n storageClass: aws_s3.StorageClass.DEEP_ARCHIVE,\n transitionAfter:\n typeof storageDriveTransition.transitionAfterDays === 'number' ? cdk.Duration.days(storageDriveTransition.transitionAfterDays) : undefined,\n transitionDate: typeof storageDriveTransition.transitionDate === 'string' ? new Date(storageDriveTransition.transitionDate) : undefined,\n});\n\nconst convertStorageDriveLifecycleRuleToAwsS3LifecycleRule = (lifecycleRule: StorageDriveLifecycleRule): aws_s3.LifecycleRule => ({\n prefix: lifecycleRule.prefix,\n expiration: lifecycleRule.deleteAfterDays ? cdk.Duration.days(lifecycleRule.deleteAfterDays) : undefined,\n objectSizeGreaterThan: lifecycleRule.fileSizeGreaterThan,\n objectSizeLessThan: lifecycleRule.fileSizeLessThan,\n transitions: lifecycleRule.transitions?.map(convertStorageDriveTransitionToAwsS3Transition),\n});\n\nexport class QpqCoreStorageDriveConstruct extends QpqCoreStorageDriveConstructBase {\n bucket: aws_s3.IBucket;\n\n static fromOtherStack(\n scope: Construct,\n id: string,\n qpqConfig: QPQConfig,\n storageDriveConfig: StorageDriveQPQConfigSetting,\n ): QpqCoreStorageDriveConstructBase {\n class Import extends QpqCoreStorageDriveConstructBase {\n bucket = aws_s3.Bucket.fromBucketName(scope, `${id}-${storageDriveConfig.uniqueKey}`, this.resourceName(storageDriveConfig.storageDrive));\n }\n\n return new Import(scope, id, { qpqConfig });\n }\n\n constructor(scope: Construct, id: string, props: QpqCoreStorageDriveConstructProps) {\n super(scope, id, props);\n\n const dataStoreRemovalPolicy = qpqConfigAwsUtils.getAwsDataStoreRemovalPolicy(props.qpqConfig);\n\n // S3_MANAGED is the floor, not an opt-in: S3 applies SSE-S3 to every bucket anyway,\n // and CDK's UNENCRYPTED member is deprecated for exactly that reason.\n let bucketEncryption: aws_s3.BucketEncryption = aws_s3.BucketEncryption.S3_MANAGED;\n let encryptionKey: aws_kms.IKey | undefined;\n if (props.storageDriveConfig.encryption) {\n const kmsCfg = qpqConfigAwsUtils.getAwsKmsKeyForStorageDrive(props.qpqConfig, props.storageDriveConfig);\n if (kmsCfg) {\n encryptionKey = aws_kms.Key.fromKeyArn(this, 'enc-key', kmsCfg.arn);\n bucketEncryption = aws_s3.BucketEncryption.KMS;\n }\n }\n\n this.bucket = new aws_s3.Bucket(this, 'bucket', {\n bucketName: this.resourceName(props.storageDriveConfig.storageDrive),\n\n // Disable public access to this bucket, CloudFront will do that\n publicReadAccess: false,\n blockPublicAccess: aws_s3.BlockPublicAccess.BLOCK_ALL,\n\n // Retain data stores by default; dev configs opt into full teardown via defineAwsDataStoreRemovalPolicy(destroy)\n removalPolicy: dataStoreRemovalPolicy === AwsDataStoreRemovalPolicy.destroy ? cdk.RemovalPolicy.DESTROY : cdk.RemovalPolicy.RETAIN,\n autoDeleteObjects: dataStoreRemovalPolicy === AwsDataStoreRemovalPolicy.destroy,\n\n // Keep prior object versions so a bad deploy / accidental overwrite can be rolled back\n versioned: true,\n\n cors: [\n {\n allowedOrigins: props.corsAllowedOrigins ?? ['*'],\n allowedMethods: [aws_s3.HttpMethods.GET, aws_s3.HttpMethods.HEAD, aws_s3.HttpMethods.PUT, aws_s3.HttpMethods.POST],\n allowedHeaders: ['*'],\n exposedHeaders: ['ETag'],\n },\n ],\n\n lifecycleRules: props.storageDriveConfig.lifecycleRules?.map(convertStorageDriveLifecycleRuleToAwsS3LifecycleRule),\n\n encryption: bucketEncryption,\n encryptionKey,\n bucketKeyEnabled: bucketEncryption === aws_s3.BucketEncryption.KMS,\n });\n\n qpqDeployAwsCdkUtils.applyEnvironmentTags(this.bucket, props.qpqConfig);\n\n const awsAccountId = qpqConfigAwsUtils.getApplicationModuleDeployAccountId(props.qpqConfig);\n\n // Account-scoped distribution/* (not the exact distribution ARN) is the ceiling\n // here: the consuming distribution lives in the web phase (its AWS-generated id\n // is unknowable at inf synth), and a bucket resource policy is a single document\n // owned by this stack — the web stack can't append to it later the way it can an\n // IAM role policy.\n if (props.allowCloudFrontRead) {\n this.bucket.addToResourcePolicy(\n new aws_iam.PolicyStatement({\n sid: 'AllowCloudFrontServicePrincipal',\n effect: aws_iam.Effect.ALLOW,\n principals: [new aws_iam.ServicePrincipal('cloudfront.amazonaws.com')],\n actions: ['s3:GetObject'],\n resources: [this.bucket.arnForObjects('*')],\n conditions: {\n StringLike: {\n 'AWS:SourceArn': `arn:aws:cloudfront::${awsAccountId}:distribution/*`,\n },\n },\n }),\n );\n }\n\n // if (props.storageDriveConfig.global) {\n // this.bucket.addToResourcePolicy(\n // new aws_iam.PolicyStatement({\n // sid: 'AllowAllEntitiesInAccount',\n // effect: aws_iam.Effect.ALLOW,\n // principals: [new aws_iam.AccountPrincipal(props.awsAccountId)],\n // actions: ['s3:GetObject', 's3:PutObject', 's3:ListBucket', 's3:DeleteObject'],\n // resources: [this.bucket.arnForObjects('*'), this.bucket.bucketArn],\n // }),\n // );\n // }\n\n if (props.storageDriveConfig.copyPath) {\n const srcDir = qpqAwsCdkPathUtils.getStorageDriveUploadFullPath(props.qpqConfig, props.storageDriveConfig);\n\n new aws_s3_deployment.BucketDeployment(this, 'bucket-deploy', {\n sources: [aws_s3_deployment.Source.asset(srcDir)],\n destinationBucket: this.bucket,\n });\n }\n }\n\n public static authorizeActionsForRole(role: aws_iam.IRole, qpqConfig: QPQConfig, ownedStorageDrives: QpqCoreStorageDriveConstruct[]) {\n // CDK-known ARNs for drives created in this stack.\n const ownedArns = ownedStorageDrives.flatMap((sd) => [sd.bucket.bucketArn, sd.bucket.arnForObjects('*')]);\n\n // Deterministically-computed ARNs for drives declared in this service's\n // config but owned by another service. Uses the same naming path as\n // `resolveStorageDriveBucketName` so no CDK cross-stack ref is created.\n const allDriveConfigs = qpqCoreUtils.getStorageDrives(qpqConfig);\n const ownedDriveConfigs = qpqCoreUtils.getOwnedStorageDrives(qpqConfig);\n const foreignDriveConfigs = allDriveConfigs.filter((cfg) => !ownedDriveConfigs.includes(cfg));\n\n const foreignArns = foreignDriveConfigs.flatMap((cfg) => {\n const bucketName = awsNamingUtils.getConfigRuntimeResourceNameFromConfigWithServiceOverride(\n cfg.owner?.resourceNameOverride || cfg.storageDrive,\n qpqConfig,\n cfg.owner?.module,\n );\n const bucketArn = `arn:aws:s3:::${bucketName}`;\n return [bucketArn, `${bucketArn}/*`];\n });\n\n const resources = [...ownedArns, ...foreignArns];\n if (resources.length === 0) return;\n\n role.addToPrincipalPolicy(\n new aws_iam.PolicyStatement({\n effect: aws_iam.Effect.ALLOW,\n actions: ['s3:GetObject', 's3:PutObject', 's3:DeleteObject', 's3:ListBucket'],\n resources,\n }),\n );\n\n // Grant KMS permissions for any encrypted drives (owned or foreign) whose\n // customer-managed key is declared in this service's config.\n const kmsArns = [...ownedDriveConfigs, ...foreignDriveConfigs]\n .filter((cfg) => cfg.encryption)\n .map((cfg) => qpqConfigAwsUtils.getAwsKmsKeyForStorageDrive(qpqConfig, cfg)?.arn)\n .filter((arn): arn is string => Boolean(arn));\n\n if (kmsArns.length > 0) {\n role.addToPrincipalPolicy(\n new aws_iam.PolicyStatement({\n effect: aws_iam.Effect.ALLOW,\n actions: ['kms:Decrypt', 'kms:GenerateDataKey*', 'kms:DescribeKey', 'kms:Encrypt', 'kms:ReEncrypt*'],\n resources: [...new Set(kmsArns)],\n }),\n );\n }\n }\n}\n"]}
1
+ {"version":3,"file":"QpqCoreStorageDriveConstruct.js","sourceRoot":"","sources":["../../../../../../src/constructs/feature/core/storageDrive/QpqCoreStorageDriveConstruct.ts"],"names":[],"mappings":"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","sourcesContent":["import { awsNamingUtils } from 'quidproquo-actionprocessor-awslambda';\nimport { AwsDataStoreRemovalPolicy, qpqConfigAwsUtils } from 'quidproquo-config-aws';\nimport { QPQConfig, qpqCoreUtils, StorageDriveLifecycleRule, StorageDriveQPQConfigSetting, StorageDriveTransition } from 'quidproquo-core';\n\nimport { aws_iam, aws_kms, aws_s3, aws_s3_deployment } from 'aws-cdk-lib';\nimport * as cdk from 'aws-cdk-lib';\nimport { Construct } from 'constructs';\n\nimport { qpqAwsCdkPathUtils } from '../../../../utils';\nimport * as qpqDeployAwsCdkUtils from '../../../../utils/qpqDeployAwsCdkUtils';\nimport { QpqConstructBlock, QpqConstructBlockProps } from '../../../base/QpqConstructBlock';\nimport { QpqResource } from '../../../base/QpqResource';\nexport interface QpqCoreStorageDriveConstructProps extends QpqConstructBlockProps {\n storageDriveConfig: StorageDriveQPQConfigSetting;\n\n /**\n * Resolved browser origins for the bucket's CORS policy. Computed by the\n * (web-aware) caller so this core construct stays domain-agnostic. Defaults\n * to '*' when omitted (headless/core-only deployments have no browser origin).\n */\n corsAllowedOrigins?: string[];\n\n /**\n * Whether this drive's bucket is served through a CloudFront distribution\n * (resolved by the web-aware caller from web entry configs). Only then does\n * the bucket policy grant CloudFront read access.\n */\n allowCloudFrontRead?: boolean;\n}\n\nexport abstract class QpqCoreStorageDriveConstructBase extends QpqConstructBlock implements QpqResource {\n abstract bucket: aws_s3.IBucket;\n\n public grantRead(grantee: aws_iam.IGrantable): aws_iam.Grant {\n return this.bucket.grantRead(grantee);\n }\n\n public grantWrite(grantee: aws_iam.IGrantable): aws_iam.Grant {\n return this.bucket.grantWrite(grantee);\n }\n\n public grantAll(grantee: aws_iam.IGrantable): void {\n this.grantRead(grantee);\n this.grantWrite(grantee);\n }\n}\n\nconst convertStorageDriveTransitionToAwsS3Transition = (storageDriveTransition: StorageDriveTransition): aws_s3.Transition => ({\n storageClass: aws_s3.StorageClass.DEEP_ARCHIVE,\n transitionAfter:\n typeof storageDriveTransition.transitionAfterDays === 'number' ? cdk.Duration.days(storageDriveTransition.transitionAfterDays) : undefined,\n transitionDate: typeof storageDriveTransition.transitionDate === 'string' ? new Date(storageDriveTransition.transitionDate) : undefined,\n});\n\nconst convertStorageDriveLifecycleRuleToAwsS3LifecycleRule = (lifecycleRule: StorageDriveLifecycleRule): aws_s3.LifecycleRule => ({\n prefix: lifecycleRule.prefix,\n expiration: lifecycleRule.deleteAfterDays ? cdk.Duration.days(lifecycleRule.deleteAfterDays) : undefined,\n objectSizeGreaterThan: lifecycleRule.fileSizeGreaterThan,\n objectSizeLessThan: lifecycleRule.fileSizeLessThan,\n transitions: lifecycleRule.transitions?.map(convertStorageDriveTransitionToAwsS3Transition),\n});\n\nexport class QpqCoreStorageDriveConstruct extends QpqCoreStorageDriveConstructBase {\n bucket: aws_s3.IBucket;\n\n static fromOtherStack(\n scope: Construct,\n id: string,\n qpqConfig: QPQConfig,\n storageDriveConfig: StorageDriveQPQConfigSetting,\n ): QpqCoreStorageDriveConstructBase {\n class Import extends QpqCoreStorageDriveConstructBase {\n bucket = aws_s3.Bucket.fromBucketName(scope, `${id}-${storageDriveConfig.uniqueKey}`, this.resourceName(storageDriveConfig.storageDrive));\n }\n\n return new Import(scope, id, { qpqConfig });\n }\n\n constructor(scope: Construct, id: string, props: QpqCoreStorageDriveConstructProps) {\n super(scope, id, props);\n\n const dataStoreRemovalPolicy = qpqConfigAwsUtils.getAwsDataStoreRemovalPolicy(props.qpqConfig);\n\n // S3_MANAGED is the floor, not an opt-in: S3 applies SSE-S3 to every bucket anyway,\n // and CDK's UNENCRYPTED member is deprecated for exactly that reason.\n let bucketEncryption: aws_s3.BucketEncryption = aws_s3.BucketEncryption.S3_MANAGED;\n let encryptionKey: aws_kms.IKey | undefined;\n if (props.storageDriveConfig.encryption) {\n const kmsCfg = qpqConfigAwsUtils.getAwsKmsKeyForStorageDrive(props.qpqConfig, props.storageDriveConfig);\n if (kmsCfg) {\n encryptionKey = aws_kms.Key.fromKeyArn(this, 'enc-key', kmsCfg.arn);\n bucketEncryption = aws_s3.BucketEncryption.KMS;\n }\n }\n\n this.bucket = new aws_s3.Bucket(this, 'bucket', {\n bucketName: this.resourceName(props.storageDriveConfig.storageDrive),\n\n // Disable public access to this bucket, CloudFront will do that\n publicReadAccess: false,\n blockPublicAccess: aws_s3.BlockPublicAccess.BLOCK_ALL,\n\n // Retain data stores by default; dev configs opt into full teardown via defineAwsDataStoreRemovalPolicy(destroy)\n removalPolicy: dataStoreRemovalPolicy === AwsDataStoreRemovalPolicy.destroy ? cdk.RemovalPolicy.DESTROY : cdk.RemovalPolicy.RETAIN,\n autoDeleteObjects: dataStoreRemovalPolicy === AwsDataStoreRemovalPolicy.destroy,\n\n // Keep prior object versions so a bad deploy / accidental overwrite can be rolled back\n versioned: true,\n\n cors: [\n {\n allowedOrigins: props.corsAllowedOrigins ?? ['*'],\n allowedMethods: [aws_s3.HttpMethods.GET, aws_s3.HttpMethods.HEAD, aws_s3.HttpMethods.PUT, aws_s3.HttpMethods.POST],\n allowedHeaders: ['*'],\n exposedHeaders: ['ETag'],\n },\n ],\n\n lifecycleRules: props.storageDriveConfig.lifecycleRules?.map(convertStorageDriveLifecycleRuleToAwsS3LifecycleRule),\n\n encryption: bucketEncryption,\n encryptionKey,\n bucketKeyEnabled: bucketEncryption === aws_s3.BucketEncryption.KMS,\n });\n\n qpqDeployAwsCdkUtils.applyEnvironmentTags(this.bucket, props.qpqConfig);\n\n const awsAccountId = qpqConfigAwsUtils.getApplicationModuleDeployAccountId(props.qpqConfig);\n\n // Account-scoped distribution/* (not the exact distribution ARN) is the ceiling\n // here: the consuming distribution lives in the web phase (its AWS-generated id\n // is unknowable at inf synth), and a bucket resource policy is a single document\n // owned by this stack — the web stack can't append to it later the way it can an\n // IAM role policy.\n if (props.allowCloudFrontRead) {\n this.bucket.addToResourcePolicy(\n new aws_iam.PolicyStatement({\n sid: 'AllowCloudFrontServicePrincipal',\n effect: aws_iam.Effect.ALLOW,\n principals: [new aws_iam.ServicePrincipal('cloudfront.amazonaws.com')],\n actions: ['s3:GetObject'],\n resources: [this.bucket.arnForObjects('*')],\n conditions: {\n StringLike: {\n 'AWS:SourceArn': `arn:aws:cloudfront::${awsAccountId}:distribution/*`,\n },\n },\n }),\n );\n }\n\n // if (props.storageDriveConfig.global) {\n // this.bucket.addToResourcePolicy(\n // new aws_iam.PolicyStatement({\n // sid: 'AllowAllEntitiesInAccount',\n // effect: aws_iam.Effect.ALLOW,\n // principals: [new aws_iam.AccountPrincipal(props.awsAccountId)],\n // actions: ['s3:GetObject', 's3:PutObject', 's3:ListBucket', 's3:DeleteObject'],\n // resources: [this.bucket.arnForObjects('*'), this.bucket.bucketArn],\n // }),\n // );\n // }\n\n if (props.storageDriveConfig.copyPath) {\n const srcDir = qpqAwsCdkPathUtils.getStorageDriveUploadFullPath(props.qpqConfig, props.storageDriveConfig);\n\n new aws_s3_deployment.BucketDeployment(this, 'bucket-deploy', {\n sources: [aws_s3_deployment.Source.asset(srcDir)],\n destinationBucket: this.bucket,\n });\n }\n }\n\n public static authorizeActionsForRole(scope: Construct, role: aws_iam.IRole, qpqConfig: QPQConfig, ownedStorageDrives: QpqCoreStorageDriveConstruct[]) {\n // CDK-known ARNs for drives created in this stack.\n const ownedArns = ownedStorageDrives.flatMap((sd) => [sd.bucket.bucketArn, sd.bucket.arnForObjects('*')]);\n\n // Deterministically-computed ARNs for drives declared in this service's\n // config but owned by another service. Uses the same naming path as\n // `resolveStorageDriveBucketName` so no CDK cross-stack ref is created.\n const allDriveConfigs = qpqCoreUtils.getStorageDrives(qpqConfig);\n const ownedDriveConfigs = qpqCoreUtils.getOwnedStorageDrives(qpqConfig);\n const foreignDriveConfigs = allDriveConfigs.filter((cfg) => !ownedDriveConfigs.includes(cfg));\n\n const foreignArns = foreignDriveConfigs.flatMap((cfg) => {\n const bucketName = awsNamingUtils.getConfigRuntimeResourceNameFromConfigWithServiceOverride(\n cfg.owner?.resourceNameOverride || cfg.storageDrive,\n qpqConfig,\n cfg.owner?.module,\n );\n const bucketArn = `arn:aws:s3:::${bucketName}`;\n return [bucketArn, `${bucketArn}/*`];\n });\n\n const resources = [...ownedArns, ...foreignArns];\n if (resources.length === 0) return;\n\n // Off the inline DefaultPolicy (10,240-byte cap) onto managed policies — the\n // drive ARN list grows with every eventDoc collection's asset bucket.\n qpqDeployAwsCdkUtils.attachManagedResourcePolicies(\n scope,\n role,\n 'webserverStorageDriveAccess',\n ['s3:GetObject', 's3:PutObject', 's3:DeleteObject', 's3:ListBucket'],\n resources,\n );\n\n // Grant KMS permissions for any encrypted drives (owned or foreign) whose\n // customer-managed key is declared in this service's config.\n const kmsArns = [...ownedDriveConfigs, ...foreignDriveConfigs]\n .filter((cfg) => cfg.encryption)\n .map((cfg) => qpqConfigAwsUtils.getAwsKmsKeyForStorageDrive(qpqConfig, cfg)?.arn)\n .filter((arn): arn is string => Boolean(arn));\n\n if (kmsArns.length > 0) {\n role.addToPrincipalPolicy(\n new aws_iam.PolicyStatement({\n effect: aws_iam.Effect.ALLOW,\n actions: ['kms:Decrypt', 'kms:GenerateDataKey*', 'kms:DescribeKey', 'kms:Encrypt', 'kms:ReEncrypt*'],\n resources: [...new Set(kmsArns)],\n }),\n );\n }\n }\n}\n"]}
@@ -21,21 +21,21 @@ class InfQpqServiceStack extends QpqServiceStack_1.QpqServiceStack {
21
21
  corsAllowedOrigins: quidproquo_webserver_1.qpqWebServerUtils.getStorageDriveCorsAllowedOrigins(props.qpqConfig, setting.storageDrive),
22
22
  allowCloudFrontRead: quidproquo_webserver_1.qpqWebServerUtils.isStorageDriveWebEntryOrigin(props.qpqConfig, setting.storageDrive),
23
23
  }));
24
- constructs_1.QpqCoreStorageDriveConstruct.authorizeActionsForRole(webserverRole, props.qpqConfig, storageDrives);
24
+ constructs_1.QpqCoreStorageDriveConstruct.authorizeActionsForRole(this, webserverRole, props.qpqConfig, storageDrives);
25
25
  // end storage drives
26
26
  // Build the parameters
27
27
  const parameters = quidproquo_core_1.qpqCoreUtils.getOwnedParameterConfigs(props.qpqConfig).map((setting) => new constructs_1.QpqCoreParameterConstruct(this, quidproquo_core_1.qpqCoreUtils.getUniqueKeyForSetting(setting), {
28
28
  qpqConfig: props.qpqConfig,
29
29
  parameterConfig: setting,
30
30
  }));
31
- constructs_1.QpqCoreParameterConstruct.authorizeActionsForRole(webserverRole, quidproquo_core_1.qpqCoreUtils.getAllParameterConfigs(props.qpqConfig), props.qpqConfig);
31
+ constructs_1.QpqCoreParameterConstruct.authorizeActionsForRole(this, webserverRole, quidproquo_core_1.qpqCoreUtils.getAllParameterConfigs(props.qpqConfig), props.qpqConfig);
32
32
  // end parameters
33
33
  // Secrets
34
34
  const secrets = quidproquo_core_1.qpqCoreUtils.getOwnedSecrets(props.qpqConfig).map((setting) => new constructs_1.QpqCoreSecretConstruct(this, quidproquo_core_1.qpqCoreUtils.getUniqueKeyForSetting(setting), {
35
35
  qpqConfig: props.qpqConfig,
36
36
  secretConfig: setting,
37
37
  }));
38
- constructs_1.QpqCoreSecretConstruct.authorizeActionsForRole(webserverRole, quidproquo_core_1.qpqCoreUtils.getAllSecretConfigs(props.qpqConfig), props.qpqConfig);
38
+ constructs_1.QpqCoreSecretConstruct.authorizeActionsForRole(this, webserverRole, quidproquo_core_1.qpqCoreUtils.getAllSecretConfigs(props.qpqConfig), props.qpqConfig);
39
39
  // end secrets
40
40
  // Queues
41
41
  const queues = quidproquo_core_1.qpqCoreUtils.getQueues(props.qpqConfig).map((setting) => new constructs_1.QpqCoreQueueConstruct(this, quidproquo_core_1.qpqCoreUtils.getUniqueKeyForSetting(setting), {
@@ -66,7 +66,7 @@ class InfQpqServiceStack extends QpqServiceStack_1.QpqServiceStack {
66
66
  qpqConfig: props.qpqConfig,
67
67
  keyValueStoreConfig: setting,
68
68
  }));
69
- constructs_1.QpqCoreKeyValueStoreConstruct.authorizeActionsForRole(webserverRole, props.qpqConfig, keyValueStores);
69
+ constructs_1.QpqCoreKeyValueStoreConstruct.authorizeActionsForRole(this, webserverRole, props.qpqConfig, keyValueStores);
70
70
  // end key value store
71
71
  // Graph Databases
72
72
  const allGraphDatabaseConfigs = quidproquo_core_1.qpqCoreUtils.getAllGraphDatabaseConfigs(props.qpqConfig);
@@ -1 +1 @@
1
- {"version":3,"file":"InfQpqServiceStack.js","sourceRoot":"","sources":["../../../src/stacks/InfQpqServiceStack.ts"],"names":[],"mappings":"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","sourcesContent":["import { qpqCoreUtils } from 'quidproquo-core';\nimport { qpqWebServerUtils } from 'quidproquo-webserver';\n\nimport { Construct } from 'constructs';\n\nimport {\n QpqCoreAiConstruct,\n QpqCoreApiGraphDatabaseConstruct,\n QpqCoreEventBusConstruct,\n QpqCoreKeyValueStoreConstruct,\n QpqCoreParameterConstruct,\n QpqCoreQueueConstruct,\n QpqCoreSecretConstruct,\n QpqCoreStorageDriveConstruct,\n QpqInfCoreUserDirectoryConstruct,\n QpqWebserverApiKeyConstruct,\n QpqWebserverCertificateConstruct,\n QpqWebserverWebsocketConstruct,\n} from '../constructs';\nimport { WebserverRoll } from '../constructs/basic/WebserverRoll';\nimport { QpqWebServerCacheConstruct } from '../constructs/feature/webserver/cache/QpqWebServerCacheConstruct';\nimport { QpqServiceStack, QpqServiceStackProps } from './base/QpqServiceStack';\n\nexport interface InfQpqServiceStackProps extends QpqServiceStackProps {}\n\nexport class InfQpqServiceStack extends QpqServiceStack {\n constructor(scope: Construct, id: string, props: InfQpqServiceStackProps) {\n super(scope, id, props);\n\n // Build the role for this service.\n const webserverRole = new WebserverRoll(this, 'webserverRoll', {\n qpqConfig: props.qpqConfig,\n }).role;\n\n // Build the storage drives\n const storageDrives = qpqCoreUtils.getOwnedStorageDrives(props.qpqConfig).map(\n (setting) =>\n new QpqCoreStorageDriveConstruct(this, qpqCoreUtils.getUniqueKeyForSetting(setting), {\n qpqConfig: props.qpqConfig,\n\n storageDriveConfig: setting,\n\n corsAllowedOrigins: qpqWebServerUtils.getStorageDriveCorsAllowedOrigins(props.qpqConfig, setting.storageDrive),\n allowCloudFrontRead: qpqWebServerUtils.isStorageDriveWebEntryOrigin(props.qpqConfig, setting.storageDrive),\n }),\n );\n QpqCoreStorageDriveConstruct.authorizeActionsForRole(webserverRole, props.qpqConfig, storageDrives);\n // end storage drives\n\n // Build the parameters\n const parameters = qpqCoreUtils.getOwnedParameterConfigs(props.qpqConfig).map(\n (setting) =>\n new QpqCoreParameterConstruct(this, qpqCoreUtils.getUniqueKeyForSetting(setting), {\n qpqConfig: props.qpqConfig,\n\n parameterConfig: setting,\n }),\n );\n QpqCoreParameterConstruct.authorizeActionsForRole(webserverRole, qpqCoreUtils.getAllParameterConfigs(props.qpqConfig), props.qpqConfig);\n // end parameters\n\n // Secrets\n const secrets = qpqCoreUtils.getOwnedSecrets(props.qpqConfig).map(\n (setting) =>\n new QpqCoreSecretConstruct(this, qpqCoreUtils.getUniqueKeyForSetting(setting), {\n qpqConfig: props.qpqConfig,\n\n secretConfig: setting,\n }),\n );\n QpqCoreSecretConstruct.authorizeActionsForRole(webserverRole, qpqCoreUtils.getAllSecretConfigs(props.qpqConfig), props.qpqConfig);\n // end secrets\n\n // Queues\n const queues = qpqCoreUtils.getQueues(props.qpqConfig).map(\n (setting) =>\n new QpqCoreQueueConstruct(this, qpqCoreUtils.getUniqueKeyForSetting(setting), {\n qpqConfig: props.qpqConfig,\n\n queueConfig: setting,\n }),\n );\n QpqCoreQueueConstruct.authorizeActionsForRole(webserverRole, queues);\n // end queues\n\n // User Directories\n const ownedUserDirectoriesConfigs = qpqCoreUtils.getOwnedUserDirectories(props.qpqConfig);\n const userDirectories = ownedUserDirectoriesConfigs.map(\n (setting) =>\n new QpqInfCoreUserDirectoryConstruct(this, qpqCoreUtils.getUniqueKeyForSetting(setting), {\n qpqConfig: props.qpqConfig,\n\n userDirectoryConfig: setting,\n }),\n );\n QpqInfCoreUserDirectoryConstruct.authorizeAdminActionsForRole(webserverRole, ownedUserDirectoriesConfigs, userDirectories, props.qpqConfig);\n\n // Api Keys\n const apiKeys = qpqWebServerUtils.getAllApiKeyConfigs(props.qpqConfig).map(\n (setting) =>\n new QpqWebserverApiKeyConstruct(this, qpqCoreUtils.getUniqueKeyForSetting(setting), {\n qpqConfig: props.qpqConfig,\n\n apiKeyConfig: setting,\n }),\n );\n\n // Event Busses\n const eventBusses = qpqCoreUtils.getOwnedEventBusConfigs(props.qpqConfig).map(\n (setting) =>\n new QpqCoreEventBusConstruct(this, qpqCoreUtils.getUniqueKeyForSetting(setting), {\n qpqConfig: props.qpqConfig,\n\n eventBusConfig: setting,\n }),\n );\n\n // key value store\n const keyValueStores = qpqCoreUtils.getOwnedKeyValueStores(props.qpqConfig).map(\n (setting) =>\n new QpqCoreKeyValueStoreConstruct(this, qpqCoreUtils.getUniqueKeyForSetting(setting), {\n qpqConfig: props.qpqConfig,\n\n keyValueStoreConfig: setting,\n }),\n );\n QpqCoreKeyValueStoreConstruct.authorizeActionsForRole(webserverRole, props.qpqConfig, keyValueStores);\n // end key value store\n\n // Graph Databases\n const allGraphDatabaseConfigs = qpqCoreUtils.getAllGraphDatabaseConfigs(props.qpqConfig);\n const graphDatabases = qpqCoreUtils.getOwnedGraphDatabases(props.qpqConfig).map(\n (setting) =>\n new QpqCoreApiGraphDatabaseConstruct(this, qpqCoreUtils.getUniqueKeyForSetting(setting), {\n qpqConfig: props.qpqConfig,\n\n graphDatabaseConfig: setting,\n }),\n );\n QpqCoreApiGraphDatabaseConstruct.authorizeActionsForRole(webserverRole, allGraphDatabaseConfigs, props.qpqConfig);\n // end key value store\n\n // AI (Bedrock)\n QpqCoreAiConstruct.authorizeActionsForRole(webserverRole, qpqCoreUtils.getAllAiConfigs(props.qpqConfig));\n // end AI\n\n // Build websocket apis\n const websockets = qpqWebServerUtils.getOwnedWebsocketSettings(props.qpqConfig).map(\n (setting) =>\n new QpqWebserverWebsocketConstruct(this, qpqCoreUtils.getUniqueKeyForSetting(setting), {\n qpqConfig: props.qpqConfig,\n\n websocketConfig: setting,\n }),\n );\n QpqWebserverWebsocketConstruct.authorizeManageConnectionsForRole(webserverRole, websockets, props.qpqConfig);\n\n // Cache settings\n const cache = qpqWebServerUtils.getAllOwnedCacheConfigs(props.qpqConfig).map(\n (setting) =>\n new QpqWebServerCacheConstruct(this, qpqCoreUtils.getUniqueKeyForSetting(setting), {\n qpqConfig: props.qpqConfig,\n\n cacheConfig: setting,\n }),\n );\n\n // Certifcates\n const certifcates = qpqWebServerUtils.getAllOwnedCertifcateConfigs(props.qpqConfig).map(\n (setting) =>\n new QpqWebserverCertificateConstruct(this, qpqCoreUtils.getUniqueKeyForSetting(setting), {\n qpqConfig: props.qpqConfig,\n\n certificateConfig: setting,\n }),\n );\n }\n}\n"]}
1
+ {"version":3,"file":"InfQpqServiceStack.js","sourceRoot":"","sources":["../../../src/stacks/InfQpqServiceStack.ts"],"names":[],"mappings":";;;AAAA,qDAA+C;AAC/C,+DAAyD;AAIzD,8CAauB;AACvB,qEAAkE;AAClE,iHAA8G;AAC9G,4DAA+E;AAI/E,MAAa,kBAAmB,SAAQ,iCAAe;IACrD,YAAY,KAAgB,EAAE,EAAU,EAAE,KAA8B;QACtE,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;QAExB,mCAAmC;QACnC,MAAM,aAAa,GAAG,IAAI,6BAAa,CAAC,IAAI,EAAE,eAAe,EAAE;YAC7D,SAAS,EAAE,KAAK,CAAC,SAAS;SAC3B,CAAC,CAAC,IAAI,CAAC;QAER,2BAA2B;QAC3B,MAAM,aAAa,GAAG,8BAAY,CAAC,qBAAqB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,CAC3E,CAAC,OAAO,EAAE,EAAE,CACV,IAAI,yCAA4B,CAAC,IAAI,EAAE,8BAAY,CAAC,sBAAsB,CAAC,OAAO,CAAC,EAAE;YACnF,SAAS,EAAE,KAAK,CAAC,SAAS;YAE1B,kBAAkB,EAAE,OAAO;YAE3B,kBAAkB,EAAE,wCAAiB,CAAC,iCAAiC,CAAC,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC,YAAY,CAAC;YAC9G,mBAAmB,EAAE,wCAAiB,CAAC,4BAA4B,CAAC,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC,YAAY,CAAC;SAC3G,CAAC,CACL,CAAC;QACF,yCAA4B,CAAC,uBAAuB,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QAC1G,qBAAqB;QAErB,uBAAuB;QACvB,MAAM,UAAU,GAAG,8BAAY,CAAC,wBAAwB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,CAC3E,CAAC,OAAO,EAAE,EAAE,CACV,IAAI,sCAAyB,CAAC,IAAI,EAAE,8BAAY,CAAC,sBAAsB,CAAC,OAAO,CAAC,EAAE;YAChF,SAAS,EAAE,KAAK,CAAC,SAAS;YAE1B,eAAe,EAAE,OAAO;SACzB,CAAC,CACL,CAAC;QACF,sCAAyB,CAAC,uBAAuB,CAAC,IAAI,EAAE,aAAa,EAAE,8BAAY,CAAC,sBAAsB,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;QAC9I,iBAAiB;QAEjB,UAAU;QACV,MAAM,OAAO,GAAG,8BAAY,CAAC,eAAe,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,CAC/D,CAAC,OAAO,EAAE,EAAE,CACV,IAAI,mCAAsB,CAAC,IAAI,EAAE,8BAAY,CAAC,sBAAsB,CAAC,OAAO,CAAC,EAAE;YAC7E,SAAS,EAAE,KAAK,CAAC,SAAS;YAE1B,YAAY,EAAE,OAAO;SACtB,CAAC,CACL,CAAC;QACF,mCAAsB,CAAC,uBAAuB,CAAC,IAAI,EAAE,aAAa,EAAE,8BAAY,CAAC,mBAAmB,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;QACxI,cAAc;QAEd,SAAS;QACT,MAAM,MAAM,GAAG,8BAAY,CAAC,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,CACxD,CAAC,OAAO,EAAE,EAAE,CACV,IAAI,kCAAqB,CAAC,IAAI,EAAE,8BAAY,CAAC,sBAAsB,CAAC,OAAO,CAAC,EAAE;YAC5E,SAAS,EAAE,KAAK,CAAC,SAAS;YAE1B,WAAW,EAAE,OAAO;SACrB,CAAC,CACL,CAAC;QACF,kCAAqB,CAAC,uBAAuB,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;QACrE,aAAa;QAEb,mBAAmB;QACnB,MAAM,2BAA2B,GAAG,8BAAY,CAAC,uBAAuB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC1F,MAAM,eAAe,GAAG,2BAA2B,CAAC,GAAG,CACrD,CAAC,OAAO,EAAE,EAAE,CACV,IAAI,6CAAgC,CAAC,IAAI,EAAE,8BAAY,CAAC,sBAAsB,CAAC,OAAO,CAAC,EAAE;YACvF,SAAS,EAAE,KAAK,CAAC,SAAS;YAE1B,mBAAmB,EAAE,OAAO;SAC7B,CAAC,CACL,CAAC;QACF,6CAAgC,CAAC,4BAA4B,CAAC,aAAa,EAAE,2BAA2B,EAAE,eAAe,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;QAE5I,WAAW;QACX,MAAM,OAAO,GAAG,wCAAiB,CAAC,mBAAmB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,CACxE,CAAC,OAAO,EAAE,EAAE,CACV,IAAI,wCAA2B,CAAC,IAAI,EAAE,8BAAY,CAAC,sBAAsB,CAAC,OAAO,CAAC,EAAE;YAClF,SAAS,EAAE,KAAK,CAAC,SAAS;YAE1B,YAAY,EAAE,OAAO;SACtB,CAAC,CACL,CAAC;QAEF,eAAe;QACf,MAAM,WAAW,GAAG,8BAAY,CAAC,uBAAuB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,CAC3E,CAAC,OAAO,EAAE,EAAE,CACV,IAAI,qCAAwB,CAAC,IAAI,EAAE,8BAAY,CAAC,sBAAsB,CAAC,OAAO,CAAC,EAAE;YAC/E,SAAS,EAAE,KAAK,CAAC,SAAS;YAE1B,cAAc,EAAE,OAAO;SACxB,CAAC,CACL,CAAC;QAEF,kBAAkB;QAClB,MAAM,cAAc,GAAG,8BAAY,CAAC,sBAAsB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,CAC7E,CAAC,OAAO,EAAE,EAAE,CACV,IAAI,0CAA6B,CAAC,IAAI,EAAE,8BAAY,CAAC,sBAAsB,CAAC,OAAO,CAAC,EAAE;YACpF,SAAS,EAAE,KAAK,CAAC,SAAS;YAE1B,mBAAmB,EAAE,OAAO;SAC7B,CAAC,CACL,CAAC;QACF,0CAA6B,CAAC,uBAAuB,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;QAC5G,sBAAsB;QAEtB,kBAAkB;QAClB,MAAM,uBAAuB,GAAG,8BAAY,CAAC,0BAA0B,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACzF,MAAM,cAAc,GAAG,8BAAY,CAAC,sBAAsB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,CAC7E,CAAC,OAAO,EAAE,EAAE,CACV,IAAI,6CAAgC,CAAC,IAAI,EAAE,8BAAY,CAAC,sBAAsB,CAAC,OAAO,CAAC,EAAE;YACvF,SAAS,EAAE,KAAK,CAAC,SAAS;YAE1B,mBAAmB,EAAE,OAAO;SAC7B,CAAC,CACL,CAAC;QACF,6CAAgC,CAAC,uBAAuB,CAAC,aAAa,EAAE,uBAAuB,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;QAClH,sBAAsB;QAEtB,eAAe;QACf,+BAAkB,CAAC,uBAAuB,CAAC,aAAa,EAAE,8BAAY,CAAC,eAAe,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;QACzG,SAAS;QAET,uBAAuB;QACvB,MAAM,UAAU,GAAG,wCAAiB,CAAC,yBAAyB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,CACjF,CAAC,OAAO,EAAE,EAAE,CACV,IAAI,2CAA8B,CAAC,IAAI,EAAE,8BAAY,CAAC,sBAAsB,CAAC,OAAO,CAAC,EAAE;YACrF,SAAS,EAAE,KAAK,CAAC,SAAS;YAE1B,eAAe,EAAE,OAAO;SACzB,CAAC,CACL,CAAC;QACF,2CAA8B,CAAC,iCAAiC,CAAC,aAAa,EAAE,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;QAE7G,iBAAiB;QACjB,MAAM,KAAK,GAAG,wCAAiB,CAAC,uBAAuB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,CAC1E,CAAC,OAAO,EAAE,EAAE,CACV,IAAI,uDAA0B,CAAC,IAAI,EAAE,8BAAY,CAAC,sBAAsB,CAAC,OAAO,CAAC,EAAE;YACjF,SAAS,EAAE,KAAK,CAAC,SAAS;YAE1B,WAAW,EAAE,OAAO;SACrB,CAAC,CACL,CAAC;QAEF,cAAc;QACd,MAAM,WAAW,GAAG,wCAAiB,CAAC,4BAA4B,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,CACrF,CAAC,OAAO,EAAE,EAAE,CACV,IAAI,6CAAgC,CAAC,IAAI,EAAE,8BAAY,CAAC,sBAAsB,CAAC,OAAO,CAAC,EAAE;YACvF,SAAS,EAAE,KAAK,CAAC,SAAS;YAE1B,iBAAiB,EAAE,OAAO;SAC3B,CAAC,CACL,CAAC;IACJ,CAAC;CACF;AAxJD,gDAwJC","sourcesContent":["import { qpqCoreUtils } from 'quidproquo-core';\nimport { qpqWebServerUtils } from 'quidproquo-webserver';\n\nimport { Construct } from 'constructs';\n\nimport {\n QpqCoreAiConstruct,\n QpqCoreApiGraphDatabaseConstruct,\n QpqCoreEventBusConstruct,\n QpqCoreKeyValueStoreConstruct,\n QpqCoreParameterConstruct,\n QpqCoreQueueConstruct,\n QpqCoreSecretConstruct,\n QpqCoreStorageDriveConstruct,\n QpqInfCoreUserDirectoryConstruct,\n QpqWebserverApiKeyConstruct,\n QpqWebserverCertificateConstruct,\n QpqWebserverWebsocketConstruct,\n} from '../constructs';\nimport { WebserverRoll } from '../constructs/basic/WebserverRoll';\nimport { QpqWebServerCacheConstruct } from '../constructs/feature/webserver/cache/QpqWebServerCacheConstruct';\nimport { QpqServiceStack, QpqServiceStackProps } from './base/QpqServiceStack';\n\nexport interface InfQpqServiceStackProps extends QpqServiceStackProps {}\n\nexport class InfQpqServiceStack extends QpqServiceStack {\n constructor(scope: Construct, id: string, props: InfQpqServiceStackProps) {\n super(scope, id, props);\n\n // Build the role for this service.\n const webserverRole = new WebserverRoll(this, 'webserverRoll', {\n qpqConfig: props.qpqConfig,\n }).role;\n\n // Build the storage drives\n const storageDrives = qpqCoreUtils.getOwnedStorageDrives(props.qpqConfig).map(\n (setting) =>\n new QpqCoreStorageDriveConstruct(this, qpqCoreUtils.getUniqueKeyForSetting(setting), {\n qpqConfig: props.qpqConfig,\n\n storageDriveConfig: setting,\n\n corsAllowedOrigins: qpqWebServerUtils.getStorageDriveCorsAllowedOrigins(props.qpqConfig, setting.storageDrive),\n allowCloudFrontRead: qpqWebServerUtils.isStorageDriveWebEntryOrigin(props.qpqConfig, setting.storageDrive),\n }),\n );\n QpqCoreStorageDriveConstruct.authorizeActionsForRole(this, webserverRole, props.qpqConfig, storageDrives);\n // end storage drives\n\n // Build the parameters\n const parameters = qpqCoreUtils.getOwnedParameterConfigs(props.qpqConfig).map(\n (setting) =>\n new QpqCoreParameterConstruct(this, qpqCoreUtils.getUniqueKeyForSetting(setting), {\n qpqConfig: props.qpqConfig,\n\n parameterConfig: setting,\n }),\n );\n QpqCoreParameterConstruct.authorizeActionsForRole(this, webserverRole, qpqCoreUtils.getAllParameterConfigs(props.qpqConfig), props.qpqConfig);\n // end parameters\n\n // Secrets\n const secrets = qpqCoreUtils.getOwnedSecrets(props.qpqConfig).map(\n (setting) =>\n new QpqCoreSecretConstruct(this, qpqCoreUtils.getUniqueKeyForSetting(setting), {\n qpqConfig: props.qpqConfig,\n\n secretConfig: setting,\n }),\n );\n QpqCoreSecretConstruct.authorizeActionsForRole(this, webserverRole, qpqCoreUtils.getAllSecretConfigs(props.qpqConfig), props.qpqConfig);\n // end secrets\n\n // Queues\n const queues = qpqCoreUtils.getQueues(props.qpqConfig).map(\n (setting) =>\n new QpqCoreQueueConstruct(this, qpqCoreUtils.getUniqueKeyForSetting(setting), {\n qpqConfig: props.qpqConfig,\n\n queueConfig: setting,\n }),\n );\n QpqCoreQueueConstruct.authorizeActionsForRole(webserverRole, queues);\n // end queues\n\n // User Directories\n const ownedUserDirectoriesConfigs = qpqCoreUtils.getOwnedUserDirectories(props.qpqConfig);\n const userDirectories = ownedUserDirectoriesConfigs.map(\n (setting) =>\n new QpqInfCoreUserDirectoryConstruct(this, qpqCoreUtils.getUniqueKeyForSetting(setting), {\n qpqConfig: props.qpqConfig,\n\n userDirectoryConfig: setting,\n }),\n );\n QpqInfCoreUserDirectoryConstruct.authorizeAdminActionsForRole(webserverRole, ownedUserDirectoriesConfigs, userDirectories, props.qpqConfig);\n\n // Api Keys\n const apiKeys = qpqWebServerUtils.getAllApiKeyConfigs(props.qpqConfig).map(\n (setting) =>\n new QpqWebserverApiKeyConstruct(this, qpqCoreUtils.getUniqueKeyForSetting(setting), {\n qpqConfig: props.qpqConfig,\n\n apiKeyConfig: setting,\n }),\n );\n\n // Event Busses\n const eventBusses = qpqCoreUtils.getOwnedEventBusConfigs(props.qpqConfig).map(\n (setting) =>\n new QpqCoreEventBusConstruct(this, qpqCoreUtils.getUniqueKeyForSetting(setting), {\n qpqConfig: props.qpqConfig,\n\n eventBusConfig: setting,\n }),\n );\n\n // key value store\n const keyValueStores = qpqCoreUtils.getOwnedKeyValueStores(props.qpqConfig).map(\n (setting) =>\n new QpqCoreKeyValueStoreConstruct(this, qpqCoreUtils.getUniqueKeyForSetting(setting), {\n qpqConfig: props.qpqConfig,\n\n keyValueStoreConfig: setting,\n }),\n );\n QpqCoreKeyValueStoreConstruct.authorizeActionsForRole(this, webserverRole, props.qpqConfig, keyValueStores);\n // end key value store\n\n // Graph Databases\n const allGraphDatabaseConfigs = qpqCoreUtils.getAllGraphDatabaseConfigs(props.qpqConfig);\n const graphDatabases = qpqCoreUtils.getOwnedGraphDatabases(props.qpqConfig).map(\n (setting) =>\n new QpqCoreApiGraphDatabaseConstruct(this, qpqCoreUtils.getUniqueKeyForSetting(setting), {\n qpqConfig: props.qpqConfig,\n\n graphDatabaseConfig: setting,\n }),\n );\n QpqCoreApiGraphDatabaseConstruct.authorizeActionsForRole(webserverRole, allGraphDatabaseConfigs, props.qpqConfig);\n // end key value store\n\n // AI (Bedrock)\n QpqCoreAiConstruct.authorizeActionsForRole(webserverRole, qpqCoreUtils.getAllAiConfigs(props.qpqConfig));\n // end AI\n\n // Build websocket apis\n const websockets = qpqWebServerUtils.getOwnedWebsocketSettings(props.qpqConfig).map(\n (setting) =>\n new QpqWebserverWebsocketConstruct(this, qpqCoreUtils.getUniqueKeyForSetting(setting), {\n qpqConfig: props.qpqConfig,\n\n websocketConfig: setting,\n }),\n );\n QpqWebserverWebsocketConstruct.authorizeManageConnectionsForRole(webserverRole, websockets, props.qpqConfig);\n\n // Cache settings\n const cache = qpqWebServerUtils.getAllOwnedCacheConfigs(props.qpqConfig).map(\n (setting) =>\n new QpqWebServerCacheConstruct(this, qpqCoreUtils.getUniqueKeyForSetting(setting), {\n qpqConfig: props.qpqConfig,\n\n cacheConfig: setting,\n }),\n );\n\n // Certifcates\n const certifcates = qpqWebServerUtils.getAllOwnedCertifcateConfigs(props.qpqConfig).map(\n (setting) =>\n new QpqWebserverCertificateConstruct(this, qpqCoreUtils.getUniqueKeyForSetting(setting), {\n qpqConfig: props.qpqConfig,\n\n certificateConfig: setting,\n }),\n );\n }\n}\n"]}
@@ -4,3 +4,4 @@ import { Construct, IConstruct } from 'constructs';
4
4
  export declare const exportStackValue: (scope: Construct, uniqueKey: string, value: string) => cdk.CfnOutput;
5
5
  export declare const importStackValue: (uniqueKey: string) => string;
6
6
  export declare const applyEnvironmentTags: (scope: IConstruct, qpqConfig: QPQConfig) => void;
7
+ export declare const attachManagedResourcePolicies: (scope: Construct, role: cdk.aws_iam.IRole, idPrefix: string, actions: string[], resources: string[]) => void;