@jaypie/constructs 1.2.59 → 1.2.60

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.
@@ -19,3 +19,4 @@ export { resolveEnvironment, EnvironmentArrayItem, EnvironmentInput, } from "./r
19
19
  export { resolveHostedZone } from "./resolveHostedZone";
20
20
  export { resolveParamsAndSecrets } from "./resolveParamsAndSecrets";
21
21
  export { resolveSecrets, SecretsArrayItem, clearSecretsCache, clearAllSecretsCaches, } from "./resolveSecrets";
22
+ export { assertValidWafRuleNames, AWS_MANAGED_RULE_GROUPS, } from "./wafManagedRuleNames";
@@ -0,0 +1,33 @@
1
+ import * as wafv2 from "aws-cdk-lib/aws-wafv2";
2
+ /**
3
+ * Canonical sub-rule names for each AWS managed rule group, as published in the
4
+ * AWS WAF developer guide. Used to validate `waf.allow` and
5
+ * `waf.managedRuleOverrides` rule names at synth time — AWS WAF matches
6
+ * `RuleActionOverride` on the exact rule *name* and silently ignores names that
7
+ * match no rule, so a typo or a label/name casing mismatch (e.g. the label
8
+ * `…:NoUserAgent_Header` vs the rule name `NoUserAgent_HEADER`) becomes an
9
+ * undiagnosable no-op.
10
+ *
11
+ * Groups absent from this map (custom rule groups, or AWS groups not yet
12
+ * mirrored here) are not validated.
13
+ *
14
+ * @see https://docs.aws.amazon.com/waf/latest/developerguide/aws-managed-rule-groups-list.html
15
+ */
16
+ export declare const AWS_MANAGED_RULE_GROUPS: Record<string, readonly string[]>;
17
+ /** One entry in a `waf.allow` list. Mirrors JaypieWafAllowEntry structurally. */
18
+ interface WafAllowEntryLike {
19
+ path: string | string[];
20
+ [ruleGroupKey: string]: string | string[] | undefined;
21
+ }
22
+ interface AssertValidWafRuleNamesOptions {
23
+ allow?: WafAllowEntryLike | WafAllowEntryLike[];
24
+ managedRuleOverrides?: Record<string, wafv2.CfnWebACL.RuleActionOverrideProperty[]>;
25
+ }
26
+ /**
27
+ * Throw a ConfigurationError if any `waf.allow` or `waf.managedRuleOverrides`
28
+ * rule name does not exist in its AWS managed rule group. Groups not present in
29
+ * AWS_MANAGED_RULE_GROUPS (custom groups) are skipped. A name that matches no
30
+ * rule would otherwise be silently ignored by AWS WAF.
31
+ */
32
+ export declare function assertValidWafRuleNames({ allow, managedRuleOverrides, }?: AssertValidWafRuleNamesOptions): void;
33
+ export {};
package/dist/esm/index.js CHANGED
@@ -1267,6 +1267,148 @@ function clearAllSecretsCaches() {
1267
1267
  // between test runs. For testing, use clearSecretsCache(scope) instead.
1268
1268
  }
1269
1269
 
1270
+ /**
1271
+ * Canonical sub-rule names for each AWS managed rule group, as published in the
1272
+ * AWS WAF developer guide. Used to validate `waf.allow` and
1273
+ * `waf.managedRuleOverrides` rule names at synth time — AWS WAF matches
1274
+ * `RuleActionOverride` on the exact rule *name* and silently ignores names that
1275
+ * match no rule, so a typo or a label/name casing mismatch (e.g. the label
1276
+ * `…:NoUserAgent_Header` vs the rule name `NoUserAgent_HEADER`) becomes an
1277
+ * undiagnosable no-op.
1278
+ *
1279
+ * Groups absent from this map (custom rule groups, or AWS groups not yet
1280
+ * mirrored here) are not validated.
1281
+ *
1282
+ * @see https://docs.aws.amazon.com/waf/latest/developerguide/aws-managed-rule-groups-list.html
1283
+ */
1284
+ const AWS_MANAGED_RULE_GROUPS = {
1285
+ AWSManagedRulesAdminProtectionRuleSet: ["AdminProtection_URIPATH"],
1286
+ AWSManagedRulesAmazonIpReputationList: [
1287
+ "AWSManagedIPDDoSList",
1288
+ "AWSManagedIPReputationList",
1289
+ "AWSManagedReconnaissanceList",
1290
+ ],
1291
+ AWSManagedRulesAnonymousIpList: ["AnonymousIPList", "HostingProviderIPList"],
1292
+ AWSManagedRulesCommonRuleSet: [
1293
+ "CrossSiteScripting_BODY",
1294
+ "CrossSiteScripting_COOKIE",
1295
+ "CrossSiteScripting_QUERYARGUMENTS",
1296
+ "CrossSiteScripting_URIPATH",
1297
+ "EC2MetaDataSSRF_BODY",
1298
+ "EC2MetaDataSSRF_COOKIE",
1299
+ "EC2MetaDataSSRF_QUERYARGUMENTS",
1300
+ "EC2MetaDataSSRF_URIPATH",
1301
+ "GenericLFI_BODY",
1302
+ "GenericLFI_QUERYARGUMENTS",
1303
+ "GenericLFI_URIPATH",
1304
+ "GenericRFI_BODY",
1305
+ "GenericRFI_QUERYARGUMENTS",
1306
+ "GenericRFI_URIPATH",
1307
+ "NoUserAgent_HEADER",
1308
+ "RestrictedExtensions_QUERYARGUMENTS",
1309
+ "RestrictedExtensions_URIPATH",
1310
+ "SizeRestrictions_BODY",
1311
+ "SizeRestrictions_Cookie_HEADER",
1312
+ "SizeRestrictions_QUERYSTRING",
1313
+ "SizeRestrictions_URIPATH",
1314
+ "UserAgent_BadBots_HEADER",
1315
+ ],
1316
+ AWSManagedRulesKnownBadInputsRuleSet: [
1317
+ "ExploitablePaths_URIPATH",
1318
+ "Host_localhost_HEADER",
1319
+ "JavaDeserializationRCE_BODY",
1320
+ "JavaDeserializationRCE_HEADER",
1321
+ "JavaDeserializationRCE_QUERYSTRING",
1322
+ "JavaDeserializationRCE_URIPATH",
1323
+ "Log4JRCE_BODY",
1324
+ "Log4JRCE_HEADER",
1325
+ "Log4JRCE_QUERYSTRING",
1326
+ "Log4JRCE_URIPATH",
1327
+ "PROPFIND_METHOD",
1328
+ "ReactJSRCE_BODY",
1329
+ ],
1330
+ AWSManagedRulesLinuxRuleSet: ["LFI_HEADER", "LFI_QUERYSTRING", "LFI_URIPATH"],
1331
+ AWSManagedRulesPHPRuleSet: [
1332
+ "PHPHighRiskMethodsVariables_BODY",
1333
+ "PHPHighRiskMethodsVariables_HEADER",
1334
+ "PHPHighRiskMethodsVariables_QUERYSTRING",
1335
+ "PHPHighRiskMethodsVariables_URIPATH",
1336
+ ],
1337
+ AWSManagedRulesSQLiRuleSet: [
1338
+ "SQLiExtendedPatterns_BODY",
1339
+ "SQLiExtendedPatterns_HEADER",
1340
+ "SQLiExtendedPatterns_QUERYARGUMENTS",
1341
+ "SQLiExtendedPatterns_URIPATH",
1342
+ "SQLi_BODY",
1343
+ "SQLi_COOKIE",
1344
+ "SQLi_QUERYARGUMENTS",
1345
+ "SQLi_URIPATH",
1346
+ ],
1347
+ AWSManagedRulesUnixRuleSet: [
1348
+ "UNIXShellCommandsVariables_BODY",
1349
+ "UNIXShellCommandsVariables_HEADER",
1350
+ "UNIXShellCommandsVariables_QUERYSTRING",
1351
+ ],
1352
+ AWSManagedRulesWindowsRuleSet: [
1353
+ "PowerShellCommands_BODY",
1354
+ "PowerShellCommands_COOKIE",
1355
+ "PowerShellCommands_QUERYARGUMENTS",
1356
+ "WindowsShellCommands_BODY",
1357
+ "WindowsShellCommands_HEADER",
1358
+ "WindowsShellCommands_QUERYARGUMENTS",
1359
+ "WindowsShellCommands_QUERYSTRING",
1360
+ "WindowsShellCommands_URIPATH",
1361
+ ],
1362
+ AWSManagedRulesWordPressRuleSet: [
1363
+ "WordPressExploitableCommands_QUERYSTRING",
1364
+ "WordPressExploitablePaths_URIPATH",
1365
+ ],
1366
+ };
1367
+ /**
1368
+ * Throw a ConfigurationError if any `waf.allow` or `waf.managedRuleOverrides`
1369
+ * rule name does not exist in its AWS managed rule group. Groups not present in
1370
+ * AWS_MANAGED_RULE_GROUPS (custom groups) are skipped. A name that matches no
1371
+ * rule would otherwise be silently ignored by AWS WAF.
1372
+ */
1373
+ function assertValidWafRuleNames({ allow, managedRuleOverrides, } = {}) {
1374
+ // Collect (group → referenced rule name) pairs from both inputs.
1375
+ const references = [];
1376
+ if (managedRuleOverrides) {
1377
+ for (const [group, overrides] of Object.entries(managedRuleOverrides)) {
1378
+ for (const override of overrides ?? []) {
1379
+ if (override?.name)
1380
+ references.push({ group, ruleName: override.name });
1381
+ }
1382
+ }
1383
+ }
1384
+ const allowEntries = allow ? (Array.isArray(allow) ? allow : [allow]) : [];
1385
+ for (const entry of allowEntries) {
1386
+ for (const key of Object.keys(entry)) {
1387
+ if (key === "path")
1388
+ continue;
1389
+ const raw = entry[key];
1390
+ if (raw == null)
1391
+ continue;
1392
+ const ruleNames = Array.isArray(raw) ? raw : [raw];
1393
+ for (const ruleName of ruleNames) {
1394
+ references.push({ group: key, ruleName });
1395
+ }
1396
+ }
1397
+ }
1398
+ for (const { group, ruleName } of references) {
1399
+ const validNames = AWS_MANAGED_RULE_GROUPS[group];
1400
+ if (!validNames)
1401
+ continue; // Unknown/custom group — cannot validate
1402
+ if (!validNames.includes(ruleName)) {
1403
+ throw new ConfigurationError(`WAF rule "${ruleName}" is not a rule in ${group}. AWS WAF matches ` +
1404
+ `RuleActionOverrides on the exact rule name and silently ignores ` +
1405
+ `unmatched names (note the label/name casing trap, e.g. ` +
1406
+ `"NoUserAgent_HEADER" not "NoUserAgent_Header"). Valid rule names: ` +
1407
+ `${validNames.join(", ")}.`);
1408
+ }
1409
+ }
1410
+ }
1411
+
1270
1412
  class JaypieApiGateway extends Construct {
1271
1413
  constructor(scope, id, props) {
1272
1414
  super(scope, id);
@@ -2760,6 +2902,8 @@ class JaypieDistribution extends Construct {
2760
2902
  else {
2761
2903
  // Create new WebACL
2762
2904
  const { allow, managedRuleOverrides, managedRuleScopeDowns, managedRules = DEFAULT_MANAGED_RULES$1, rateLimitPerIp = DEFAULT_RATE_LIMIT$1, } = wafConfig;
2905
+ // Fail synth on rule names AWS WAF would silently ignore (#362)
2906
+ assertValidWafRuleNames({ allow, managedRuleOverrides });
2763
2907
  const allowEntries = allow
2764
2908
  ? Array.isArray(allow)
2765
2909
  ? allow
@@ -4746,6 +4890,8 @@ class JaypieWebDeploymentBucket extends Construct {
4746
4890
  }
4747
4891
  else {
4748
4892
  const { managedRuleOverrides, managedRuleScopeDowns, managedRules = DEFAULT_MANAGED_RULES, rateLimitPerIp = DEFAULT_RATE_LIMIT, } = wafConfig;
4893
+ // Fail synth on rule names AWS WAF would silently ignore (#362)
4894
+ assertValidWafRuleNames({ managedRuleOverrides });
4749
4895
  let priority = 0;
4750
4896
  const rules = [];
4751
4897
  for (const ruleName of managedRules) {
@@ -5419,5 +5565,5 @@ class JaypieWebSocketTable extends Construct {
5419
5565
  }
5420
5566
  }
5421
5567
 
5422
- export { CDK$2 as CDK, JaypieAccountLoggingBucket, JaypieApiGateway, JaypieAppStack, JaypieBucketQueuedLambda, JaypieCertificate, JaypieDatadogBucket, JaypieDatadogForwarder, JaypieDatadogSecret, JaypieDistribution, JaypieDnsRecord, JaypieDynamoDb, JaypieEnvSecret, JaypieEventsRule, JaypieExpressLambda, JaypieGitHubDeployRole, JaypieHostedZone, JaypieInfrastructureStack, JaypieLambda, JaypieMigration, JaypieMongoDbSecret, JaypieNextJs, JaypieOpenAiSecret, JaypieOrganizationTrail, JaypieQueuedLambda, JaypieSecret, JaypieSsoPermissions, JaypieSsoSyncApplication, JaypieStack, JaypieStaticWebBucket, JaypieTraceSigningKeySecret, JaypieWebDeploymentBucket, JaypieWebSocket, JaypieWebSocketLambda, JaypieWebSocketTable, addDatadogLayers, clearAllCertificateCaches, clearAllSecretsCaches, clearCertificateCache, clearSecretsCache, constructEnvName, constructStackName, constructTagger, constructWafLogBucketName, ensureRoute53QueryLoggingPolicy, envHostname, extendDatadogRole, isEnv, isProductionEnv, isSandboxEnv, isValidHostname$1 as isValidHostname, isValidSubdomain, jaypieLambdaEnv, mergeDomain, resolveCertificate, resolveDatadogForwarderFunction, resolveDatadogLayers, resolveDatadogLoggingDestination, resolveEnvironment, resolveHostedZone, resolveParamsAndSecrets, resolveSecrets };
5568
+ export { AWS_MANAGED_RULE_GROUPS, CDK$2 as CDK, JaypieAccountLoggingBucket, JaypieApiGateway, JaypieAppStack, JaypieBucketQueuedLambda, JaypieCertificate, JaypieDatadogBucket, JaypieDatadogForwarder, JaypieDatadogSecret, JaypieDistribution, JaypieDnsRecord, JaypieDynamoDb, JaypieEnvSecret, JaypieEventsRule, JaypieExpressLambda, JaypieGitHubDeployRole, JaypieHostedZone, JaypieInfrastructureStack, JaypieLambda, JaypieMigration, JaypieMongoDbSecret, JaypieNextJs, JaypieOpenAiSecret, JaypieOrganizationTrail, JaypieQueuedLambda, JaypieSecret, JaypieSsoPermissions, JaypieSsoSyncApplication, JaypieStack, JaypieStaticWebBucket, JaypieTraceSigningKeySecret, JaypieWebDeploymentBucket, JaypieWebSocket, JaypieWebSocketLambda, JaypieWebSocketTable, addDatadogLayers, assertValidWafRuleNames, clearAllCertificateCaches, clearAllSecretsCaches, clearCertificateCache, clearSecretsCache, constructEnvName, constructStackName, constructTagger, constructWafLogBucketName, ensureRoute53QueryLoggingPolicy, envHostname, extendDatadogRole, isEnv, isProductionEnv, isSandboxEnv, isValidHostname$1 as isValidHostname, isValidSubdomain, jaypieLambdaEnv, mergeDomain, resolveCertificate, resolveDatadogForwarderFunction, resolveDatadogLayers, resolveDatadogLoggingDestination, resolveEnvironment, resolveHostedZone, resolveParamsAndSecrets, resolveSecrets };
5423
5569
  //# sourceMappingURL=index.js.map