@kensio/yulin 1.21.22 → 1.21.24

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 (104) hide show
  1. package/dist/service/athena/engine/sim-athena-ast-nodes.d.ts +11 -0
  2. package/dist/service/athena/engine/sim-athena-ast-nodes.js +22 -0
  3. package/dist/service/athena/engine/sim-athena-string-shims.js +29 -1
  4. package/dist/service/athena/engine/sim-athena-unnest-item.js +6 -15
  5. package/dist/service/athena/engine/sim-athena-unnest-rewrite.d.ts +4 -4
  6. package/dist/service/athena/engine/sim-athena-unnest-rewrite.js +4 -4
  7. package/dist/service/athena/engine/sim-athena-unnest-source.d.ts +10 -9
  8. package/dist/service/athena/engine/sim-athena-unnest-source.js +25 -11
  9. package/dist/service/athena/sim-athena-flattened-events.fixture.d.ts +3 -0
  10. package/dist/service/athena/sim-athena-flattened-events.fixture.js +46 -0
  11. package/dist/service/wafv2/association/sim-aws-waf-protected-resources.js +4 -0
  12. package/dist/service/wafv2/association/sim-waf-associations.d.ts +6 -0
  13. package/dist/service/wafv2/association/sim-waf-associations.js +17 -0
  14. package/dist/service/wafv2/association/sim-waf-protected-resource.d.ts +13 -8
  15. package/dist/service/wafv2/association/sim-waf-protected-resource.js +23 -23
  16. package/dist/service/wafv2/association/sim-waf-protected-resources.d.ts +11 -6
  17. package/dist/service/wafv2/association/sim-waf-protected-resources.js +10 -7
  18. package/dist/service/wafv2/association/sim-waf-unsimulated-resource.d.ts +33 -0
  19. package/dist/service/wafv2/association/sim-waf-unsimulated-resource.js +66 -0
  20. package/dist/service/wafv2/cfn/association/sim-cfn-waf-association-creator.js +5 -0
  21. package/dist/service/wafv2/cfn/ip-set/sim-cfn-waf-ip-set-config.js +1 -0
  22. package/dist/service/wafv2/cfn/ip-set/sim-cfn-waf-ip-set-creator.js +2 -0
  23. package/dist/service/wafv2/cfn/regex-pattern-set/sim-cfn-waf-regex-set-config.js +1 -0
  24. package/dist/service/wafv2/cfn/regex-pattern-set/sim-cfn-waf-regex-set-creator.js +2 -0
  25. package/dist/service/wafv2/cfn/sim-cfn-waf-resource-config.d.ts +4 -0
  26. package/dist/service/wafv2/cfn/sim-cfn-waf-resource-config.js +10 -0
  27. package/dist/service/wafv2/cfn/sim-cfn-waf-unsimulated.d.ts +10 -0
  28. package/dist/service/wafv2/cfn/sim-cfn-waf-unsimulated.js +12 -0
  29. package/dist/service/wafv2/cfn/web-acl/sim-cfn-waf-web-acl-config.d.ts +1 -13
  30. package/dist/service/wafv2/cfn/web-acl/sim-cfn-waf-web-acl-config.js +8 -21
  31. package/dist/service/wafv2/cfn/web-acl/sim-cfn-waf-web-acl-creator.d.ts +4 -9
  32. package/dist/service/wafv2/cfn/web-acl/sim-cfn-waf-web-acl-creator.js +7 -15
  33. package/dist/service/wafv2/command/association/sim-wafv2-association-commands.js +2 -1
  34. package/dist/service/wafv2/command/association/sim-wafv2-association-input.d.ts +10 -2
  35. package/dist/service/wafv2/command/association/sim-wafv2-association-input.js +25 -13
  36. package/dist/service/wafv2/command/ip-set/sim-wafv2-ip-set-commands.d.ts +3 -3
  37. package/dist/service/wafv2/command/ip-set/sim-wafv2-ip-set-commands.js +5 -5
  38. package/dist/service/wafv2/command/managed-rule-group/sim-wafv2-managed-rule-group-commands.js +4 -4
  39. package/dist/service/wafv2/command/regex-pattern-set/sim-wafv2-regex-pattern-set-commands.js +2 -2
  40. package/dist/service/wafv2/command/sim-wafv2-input.d.ts +0 -7
  41. package/dist/service/wafv2/command/sim-wafv2-input.js +1 -13
  42. package/dist/service/wafv2/command/web-acl/sim-waf-web-acl-output.js +1 -0
  43. package/dist/service/wafv2/command/web-acl/sim-wafv2-unsimulated-web-acl-input.d.ts +9 -12
  44. package/dist/service/wafv2/command/web-acl/sim-wafv2-unsimulated-web-acl-input.js +27 -28
  45. package/dist/service/wafv2/command/web-acl/sim-wafv2-web-acl-commands.d.ts +3 -3
  46. package/dist/service/wafv2/command/web-acl/sim-wafv2-web-acl-commands.js +6 -6
  47. package/dist/service/wafv2/command/web-acl/web-acl.command.d.ts +6 -0
  48. package/dist/service/wafv2/index.d.ts +3 -0
  49. package/dist/service/wafv2/index.js +1 -0
  50. package/dist/service/wafv2/managed/group/sim-waf-bot-control.d.ts +27 -0
  51. package/dist/service/wafv2/managed/group/sim-waf-bot-control.js +68 -0
  52. package/dist/service/wafv2/managed/group/sim-waf-ip-reputation.d.ts +18 -0
  53. package/dist/service/wafv2/managed/group/sim-waf-ip-reputation.js +51 -0
  54. package/dist/service/wafv2/managed/sim-waf-bot-declaration.d.ts +35 -0
  55. package/dist/service/wafv2/managed/sim-waf-bot-declaration.js +42 -0
  56. package/dist/service/wafv2/managed/sim-waf-managed-declaration.d.ts +35 -0
  57. package/dist/service/wafv2/managed/sim-waf-managed-declaration.js +30 -0
  58. package/dist/service/wafv2/managed/sim-waf-managed-group-configs.d.ts +11 -0
  59. package/dist/service/wafv2/managed/sim-waf-managed-group-configs.js +42 -0
  60. package/dist/service/wafv2/managed/sim-waf-managed-group-input.d.ts +5 -4
  61. package/dist/service/wafv2/managed/sim-waf-managed-group-input.js +7 -9
  62. package/dist/service/wafv2/managed/sim-waf-managed-group-statement.js +16 -14
  63. package/dist/service/wafv2/managed/sim-waf-managed-group.type.d.ts +2 -2
  64. package/dist/service/wafv2/managed/sim-waf-managed-rule-actions.d.ts +30 -0
  65. package/dist/service/wafv2/managed/sim-waf-managed-rule-actions.js +26 -0
  66. package/dist/service/wafv2/managed/sim-waf-managed-rule-groups.d.ts +5 -3
  67. package/dist/service/wafv2/managed/sim-waf-managed-rule-groups.js +10 -3
  68. package/dist/service/wafv2/managed/sim-waf-managed-rule.type.d.ts +11 -2
  69. package/dist/service/wafv2/managed/sim-waf-managed-rules.d.ts +14 -9
  70. package/dist/service/wafv2/managed/sim-waf-managed-rules.js +15 -5
  71. package/dist/service/wafv2/resource/sim-waf-resource.d.ts +10 -0
  72. package/dist/service/wafv2/resource/sim-waf-resource.js +12 -0
  73. package/dist/service/wafv2/resource/sim-waf-unsimulated-part.d.ts +24 -0
  74. package/dist/service/wafv2/resource/sim-waf-unsimulated-part.js +8 -0
  75. package/dist/service/wafv2/sim-wafv2.d.ts +12 -12
  76. package/dist/service/wafv2/sim-wafv2.fixture.d.ts +19 -1
  77. package/dist/service/wafv2/sim-wafv2.fixture.js +29 -0
  78. package/dist/service/wafv2/sim-wafv2.js +25 -23
  79. package/dist/service/wafv2/statement/sim-waf-field-to-match.type.d.ts +2 -2
  80. package/dist/service/wafv2/statement/sim-waf-rule-refusals.d.ts +6 -4
  81. package/dist/service/wafv2/statement/sim-waf-rule-refusals.js +7 -6
  82. package/dist/service/wafv2/statement/sim-waf-statement.d.ts +3 -3
  83. package/dist/service/wafv2/statement/sim-waf-statement.js +3 -3
  84. package/dist/service/wafv2/statement/sim-waf-statement.type.d.ts +3 -3
  85. package/dist/service/wafv2/statement/sim-waf-unsimulated-statement.js +1 -1
  86. package/dist/service/wafv2/web-acl/sim-waf-association-config.d.ts +14 -7
  87. package/dist/service/wafv2/web-acl/sim-waf-association-config.js +17 -27
  88. package/dist/service/wafv2/web-acl/sim-waf-rule.d.ts +15 -3
  89. package/dist/service/wafv2/web-acl/sim-waf-rule.js +46 -10
  90. package/dist/service/wafv2/web-acl/sim-waf-statement-capacity.d.ts +4 -4
  91. package/dist/service/wafv2/web-acl/sim-waf-statement-capacity.js +4 -4
  92. package/dist/service/wafv2/web-acl/sim-waf-unsimulated-body-limit.d.ts +6 -0
  93. package/dist/service/wafv2/web-acl/sim-waf-unsimulated-body-limit.js +23 -0
  94. package/dist/service/wafv2/web-acl/sim-waf-web-acl-capacity.js +2 -2
  95. package/dist/service/wafv2/web-acl/sim-waf-web-acl-configuration.d.ts +5 -0
  96. package/dist/service/wafv2/web-acl/sim-waf-web-acl.d.ts +11 -2
  97. package/dist/service/wafv2/web-acl/sim-waf-web-acl.js +20 -1
  98. package/docs/services/athena/README.md +21 -2
  99. package/docs/services/wafv2/README.md +243 -51
  100. package/package.json +2 -2
  101. package/dist/service/wafv2/cfn/web-acl/sim-cfn-waf-evaluatable-rules.d.ts +0 -15
  102. package/dist/service/wafv2/cfn/web-acl/sim-cfn-waf-evaluatable-rules.js +0 -21
  103. package/dist/service/wafv2/web-acl/sim-waf-unevaluatable-rules.d.ts +0 -25
  104. package/dist/service/wafv2/web-acl/sim-waf-unevaluatable-rules.js +0 -33
@@ -1,16 +1,17 @@
1
1
  import { SimWafInvalidParameterException, SimWafUnsimulatedInputException, } from "../error/sim-wafv2.error.js";
2
2
  /**
3
- * Refuse something in a rule that real WAFv2 takes and this simulation does
3
+ * Stop compiling a rule at something real WAFv2 takes and this simulation does
4
4
  * not.
5
5
  *
6
- * Every refusal names the rule and what in it was refused, because a web ACL
7
- * is a list of rules that all look alike from the outside and the name is the
8
- * only thing that says which one to go and look at.
6
+ * `SimWafRule.compile` catches it and holds the rule unevaluated, with this
7
+ * message as the reason the web ACL reports. The message names the rule and
8
+ * what in it was left out, because a web ACL is a list of rules that all look
9
+ * alike from the outside and the name is the only thing that says which one to
10
+ * go and look at.
9
11
  */
10
12
  export function refuseSimWafRuleInput(ruleName, refused, reason) {
11
13
  throw new SimWafUnsimulatedInputException(`Rule ${ruleName} uses ${refused}, which Yulin does not simulate: ` +
12
- `${reason}. A web ACL that accepted a rule it cannot evaluate would ` +
13
- `allow a request AWS blocks.`);
14
+ `${reason}. The rule is held and claims no request.`);
14
15
  }
15
16
  /**
16
17
  * Refuse a rule real WAFv2 would refuse too.
@@ -19,8 +19,8 @@ export interface SimWafStatementScope {
19
19
  * Turn one statement into the matcher a rule evaluates a request with.
20
20
  *
21
21
  * Compiling happens when the web ACL is written rather than when a request
22
- * arrives, which is what lets `CreateWebACL` refuse a statement kind it cannot
23
- * evaluate. It also means a rule does no parsing per request: what a request
24
- * meets is a closure over what the rule already worked out.
22
+ * arrives, which is where a statement kind Yulin cannot evaluate is found and
23
+ * its rule held unevaluated. It also means a rule does no parsing per request:
24
+ * what a request meets is a closure over what the rule already worked out.
25
25
  */
26
26
  export declare function compileSimWafStatement(statement: SimWafStatementInput | undefined, scope: SimWafStatementScope): SimWafMatcher;
@@ -11,9 +11,9 @@ import { refuseUnsimulatedSimWafStatement } from "./sim-waf-unsimulated-statemen
11
11
  * Turn one statement into the matcher a rule evaluates a request with.
12
12
  *
13
13
  * Compiling happens when the web ACL is written rather than when a request
14
- * arrives, which is what lets `CreateWebACL` refuse a statement kind it cannot
15
- * evaluate. It also means a rule does no parsing per request: what a request
16
- * meets is a closure over what the rule already worked out.
14
+ * arrives, which is where a statement kind Yulin cannot evaluate is found and
15
+ * its rule held unevaluated. It also means a rule does no parsing per request:
16
+ * what a request meets is a closure over what the rule already worked out.
17
17
  */
18
18
  export function compileSimWafStatement(statement, scope) {
19
19
  const { ruleName } = scope;
@@ -16,9 +16,9 @@ export interface SimWafFieldStatementInput {
16
16
  /**
17
17
  * Minimal structural WAFv2 Statement.
18
18
  *
19
- * The kinds Yulin refuses are declared alongside the ones it evaluates, so a
20
- * rule that uses one is refused by name rather than read as a rule with no
21
- * statement in it.
19
+ * The kinds Yulin does not evaluate are declared alongside the ones it does,
20
+ * so a rule that uses one is held and reported by name rather than read as a
21
+ * rule with no statement in it.
22
22
  *
23
23
  * https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/wafv2/Interface/Statement/
24
24
  */
@@ -6,7 +6,7 @@ const undocumentedDetection = "AWS does not document the detection it runs, so a
6
6
  "agree with real WAF by coincidence or not at all";
7
7
  /**
8
8
  * The statement kinds real WAFv2 evaluates and this simulation does not, and
9
- * why each of them is refused rather than deferred.
9
+ * why a rule using one is held unevaluated.
10
10
  */
11
11
  const refusedStatements = new Map([
12
12
  ["IPSetReferenceStatement", oneClientAddress],
@@ -1,10 +1,11 @@
1
+ import type { SimWafUnsimulatedPart } from "../resource/sim-waf-unsimulated-part.js";
1
2
  /**
2
3
  * A resource type whose body inspection limit a web ACL can set.
3
4
  *
4
5
  * Real WAF keys `AssociationConfig.RequestBody` by resource type, and these
5
- * three are the ones a web ACL goes in front of here. `APP_RUNNER_SERVICE` and
6
- * `VERIFIED_ACCESS_INSTANCE` are keys AWS takes for resources this simulation
7
- * has no association for.
6
+ * three are the ones a request reaches a web ACL through here. `APP_RUNNER_SERVICE`
7
+ * and `VERIFIED_ACCESS_INSTANCE` are keys AWS takes for resources a web ACL
8
+ * can be associated with and no simulated request passes through.
8
9
  */
9
10
  export type SimWafBodyInspectionResourceType = "CLOUDFRONT" | "API_GATEWAY" | "COGNITO_USER_POOL";
10
11
  /**
@@ -12,8 +13,8 @@ export type SimWafBodyInspectionResourceType = "CLOUDFRONT" | "API_GATEWAY" | "C
12
13
  * `AssociationConfig`.
13
14
  *
14
15
  * CloudFront, API Gateway and Cognito all default to 16 KB. A load balancer
15
- * and an AppSync API are fixed at 8 KB, and a web ACL cannot be put in front
16
- * of either one here.
16
+ * and an AppSync API are fixed at 8 KB, and no simulated request reaches a web
17
+ * ACL through either one.
17
18
  */
18
19
  export declare const simWafBodyInspectionLimitBytes = 16384;
19
20
  /**
@@ -40,9 +41,15 @@ export declare class SimWafBodyInspectionLimits {
40
41
  private constructor();
41
42
  /**
42
43
  * Read the limits an `AssociationConfig` sets, refusing anything WAF would
43
- * refuse and anything this simulation cannot apply.
44
+ * refuse.
44
45
  */
45
46
  static read(input: SimWafAssociationConfigInput | undefined): SimWafBodyInspectionLimits;
47
+ /**
48
+ * The limits set for resource types no simulated request passes through.
49
+ *
50
+ * Each is checked as WAF checks it and held, and applies to nothing.
51
+ */
52
+ get unsimulated(): readonly SimWafUnsimulatedPart[];
46
53
  /**
47
54
  * How many bytes of a body a request reaching one resource type is inspected
48
55
  * for.
@@ -50,5 +57,5 @@ export declare class SimWafBodyInspectionLimits {
50
57
  * A request evaluated against a web ACL that no resource holds names no
51
58
  * resource type, and reads the default.
52
59
  */
53
- bytesFor(resourceType: SimWafBodyInspectionResourceType | undefined): number;
60
+ bytesFor(resourceType: string | undefined): number;
54
61
  }
@@ -1,11 +1,12 @@
1
- import { SimWafInvalidParameterException, SimWafUnsimulatedInputException, } from "../error/sim-wafv2.error.js";
1
+ import { SimWafInvalidParameterException } from "../error/sim-wafv2.error.js";
2
+ import { unsimulatedSimWafBodyLimits } from "./sim-waf-unsimulated-body-limit.js";
2
3
  /**
3
4
  * How much of a request body WAF reads for a resource type given no
4
5
  * `AssociationConfig`.
5
6
  *
6
7
  * CloudFront, API Gateway and Cognito all default to 16 KB. A load balancer
7
- * and an AppSync API are fixed at 8 KB, and a web ACL cannot be put in front
8
- * of either one here.
8
+ * and an AppSync API are fixed at 8 KB, and no simulated request reaches a web
9
+ * ACL through either one.
9
10
  */
10
11
  export const simWafBodyInspectionLimitBytes = 16_384;
11
12
  /**
@@ -17,11 +18,6 @@ const inspectionLimits = new Map([
17
18
  ["KB_48", 49_152],
18
19
  ["KB_64", 65_536],
19
20
  ]);
20
- const simulatedResourceTypes = [
21
- "CLOUDFRONT",
22
- "API_GATEWAY",
23
- "COGNITO_USER_POOL",
24
- ];
25
21
  /**
26
22
  * How much of a request body a web ACL's rules read, by resource type.
27
23
  *
@@ -36,15 +32,21 @@ export class SimWafBodyInspectionLimits {
36
32
  }
37
33
  /**
38
34
  * Read the limits an `AssociationConfig` sets, refusing anything WAF would
39
- * refuse and anything this simulation cannot apply.
35
+ * refuse.
40
36
  */
41
37
  static read(input) {
42
- const configured = Object.entries(input?.RequestBody ?? {});
43
- const limits = new Map();
44
- for (const [resourceType, config] of configured) {
45
- limits.set(simulatedResourceType(resourceType), inspectionLimit(resourceType, config));
46
- }
47
- return new SimWafBodyInspectionLimits(limits);
38
+ return new SimWafBodyInspectionLimits(new Map(Object.entries(input?.RequestBody ?? {}).map(([resourceType, config]) => [
39
+ resourceType,
40
+ inspectionLimit(resourceType, config),
41
+ ])));
42
+ }
43
+ /**
44
+ * The limits set for resource types no simulated request passes through.
45
+ *
46
+ * Each is checked as WAF checks it and held, and applies to nothing.
47
+ */
48
+ get unsimulated() {
49
+ return unsimulatedSimWafBodyLimits(this.limits.keys());
48
50
  }
49
51
  /**
50
52
  * How many bytes of a body a request reaching one resource type is inspected
@@ -60,18 +62,6 @@ export class SimWafBodyInspectionLimits {
60
62
  return this.limits.get(resourceType) ?? simWafBodyInspectionLimitBytes;
61
63
  }
62
64
  }
63
- /**
64
- * Hold a `RequestBody` key to the resource types this simulation associates.
65
- */
66
- function simulatedResourceType(resourceType) {
67
- const simulated = simulatedResourceTypes.find((candidate) => candidate === resourceType);
68
- if (simulated === undefined) {
69
- throw new SimWafUnsimulatedInputException(`AssociationConfig sets the body inspection limit for ${resourceType} ` +
70
- `resources, and ${simulatedResourceTypes.join(" and ")} are the ` +
71
- `types a web ACL goes in front of in Yulin`);
72
- }
73
- return simulated;
74
- }
75
65
  /**
76
66
  * Read one resource type's `DefaultSizeInspectionLimit`.
77
67
  *
@@ -4,17 +4,29 @@ import type { SimWafRuleInput, SimWafRuleScope } from "./sim-waf-rule.type.js";
4
4
  /**
5
5
  * One rule of a web ACL, compiled so a request can be evaluated against it.
6
6
  *
7
- * The statement is turned into an evaluator when the web ACL is written, which
8
- * is what lets a rule Yulin cannot evaluate be refused at that point rather
9
- * than silently letting requests past later on.
7
+ * The statement is turned into an evaluator when the web ACL is written. A
8
+ * rule using something Yulin does not simulate is held all the same, as a
9
+ * rule that claims no request, and says why in `unsimulatedReason`. The web
10
+ * ACL reports it from there.
10
11
  */
11
12
  export declare class SimWafRule {
12
13
  #private;
13
14
  readonly name: string;
14
15
  readonly priority: number;
16
+ /**
17
+ * Why this rule claims no request, when it uses something Yulin does not
18
+ * simulate.
19
+ *
20
+ * AWS would evaluate it. A request it would have claimed goes on to the
21
+ * next rule here.
22
+ */
23
+ readonly unsimulatedReason: string | undefined;
15
24
  private constructor();
16
25
  /**
17
26
  * Compile one rule as it was written.
27
+ *
28
+ * Input WAFv2 itself would refuse is refused here too. A rule using
29
+ * something only Yulin leaves out compiles to one that claims nothing.
18
30
  */
19
31
  static compile(input: SimWafRuleInput, scope: SimWafRuleScope): SimWafRule;
20
32
  /**
@@ -1,16 +1,32 @@
1
+ import { SimWafUnsimulatedInputException } from "../error/sim-wafv2.error.js";
1
2
  import { refuseUnsimulatedSimWafRuleInput, requiredSimWafRuleName, requiredSimWafRulePriority, } from "./sim-waf-rule-input.js";
2
3
  import { simWafRuleLabels } from "./sim-waf-rule-labels.js";
3
4
  import { compileSimWafRuleEvaluator } from "./sim-waf-rule-evaluator.js";
5
+ /**
6
+ * What a rule held without being evaluated does with every request.
7
+ */
8
+ function claimsNothing() {
9
+ // A held rule claims no request, so every request goes on to the next rule.
10
+ }
4
11
  /**
5
12
  * One rule of a web ACL, compiled so a request can be evaluated against it.
6
13
  *
7
- * The statement is turned into an evaluator when the web ACL is written, which
8
- * is what lets a rule Yulin cannot evaluate be refused at that point rather
9
- * than silently letting requests past later on.
14
+ * The statement is turned into an evaluator when the web ACL is written. A
15
+ * rule using something Yulin does not simulate is held all the same, as a
16
+ * rule that claims no request, and says why in `unsimulatedReason`. The web
17
+ * ACL reports it from there.
10
18
  */
11
19
  export class SimWafRule {
12
20
  name;
13
21
  priority;
22
+ /**
23
+ * Why this rule claims no request, when it uses something Yulin does not
24
+ * simulate.
25
+ *
26
+ * AWS would evaluate it. A request it would have claimed goes on to the
27
+ * next rule here.
28
+ */
29
+ unsimulatedReason;
14
30
  #labels;
15
31
  #evaluate;
16
32
  constructor(properties) {
@@ -18,19 +34,39 @@ export class SimWafRule {
18
34
  this.priority = properties.priority;
19
35
  this.#labels = properties.labels;
20
36
  this.#evaluate = properties.evaluate;
37
+ this.unsimulatedReason = properties.unsimulatedReason;
21
38
  }
22
39
  /**
23
40
  * Compile one rule as it was written.
41
+ *
42
+ * Input WAFv2 itself would refuse is refused here too. A rule using
43
+ * something only Yulin leaves out compiles to one that claims nothing.
24
44
  */
25
45
  static compile(input, scope) {
26
46
  const name = requiredSimWafRuleName(input.Name);
27
- refuseUnsimulatedSimWafRuleInput(input, name);
28
- return new SimWafRule({
29
- name,
30
- priority: requiredSimWafRulePriority(input.Priority, name),
31
- labels: simWafRuleLabels(input.RuleLabels, name),
32
- evaluate: compileSimWafRuleEvaluator(input, name, scope),
33
- });
47
+ const priority = requiredSimWafRulePriority(input.Priority, name);
48
+ const labels = simWafRuleLabels(input.RuleLabels, name);
49
+ try {
50
+ refuseUnsimulatedSimWafRuleInput(input, name);
51
+ return new SimWafRule({
52
+ name,
53
+ priority,
54
+ labels,
55
+ evaluate: compileSimWafRuleEvaluator(input, name, scope),
56
+ });
57
+ }
58
+ catch (error) {
59
+ if (!(error instanceof SimWafUnsimulatedInputException)) {
60
+ throw error;
61
+ }
62
+ return new SimWafRule({
63
+ name,
64
+ priority,
65
+ labels,
66
+ evaluate: claimsNothing,
67
+ unsimulatedReason: error.message,
68
+ });
69
+ }
34
70
  }
35
71
  /**
36
72
  * What this rule does with a request, which is nothing when it does not
@@ -2,9 +2,9 @@ import type { SimWafStatementInput } from "../statement/sim-waf-statement.type.j
2
2
  /**
3
3
  * What the statements that inspect a request cost.
4
4
  *
5
- * Only the kinds this simulation evaluates are counted. Every other kind is
6
- * refused where the rule is written, so a web ACL that has rules to add up
7
- * cannot hold one. Doubling the base cost for a JSON body never applies here
8
- * for the same reason.
5
+ * Only the kinds this simulation evaluates are counted. A rule using any
6
+ * other kind is held unevaluated and contributes nothing, so a web ACL holding
7
+ * one reports less than AWS would charge. Doubling the base cost for a JSON
8
+ * body never applies here for the same reason.
9
9
  */
10
10
  export declare function simWafMatchCapacity(statement: SimWafStatementInput): number;
@@ -19,10 +19,10 @@ const textTransformationCost = 10;
19
19
  /**
20
20
  * What the statements that inspect a request cost.
21
21
  *
22
- * Only the kinds this simulation evaluates are counted. Every other kind is
23
- * refused where the rule is written, so a web ACL that has rules to add up
24
- * cannot hold one. Doubling the base cost for a JSON body never applies here
25
- * for the same reason.
22
+ * Only the kinds this simulation evaluates are counted. A rule using any
23
+ * other kind is held unevaluated and contributes nothing, so a web ACL holding
24
+ * one reports less than AWS would charge. Doubling the base cost for a JSON
25
+ * body never applies here for the same reason.
26
26
  */
27
27
  export function simWafMatchCapacity(statement) {
28
28
  return (byteMatchCapacity(statement.ByteMatchStatement) +
@@ -0,0 +1,6 @@
1
+ import type { SimWafUnsimulatedPart } from "../resource/sim-waf-unsimulated-part.js";
2
+ /**
3
+ * What the body inspection limits a web ACL sets leave out, one part per
4
+ * resource type no simulated request passes through.
5
+ */
6
+ export declare function unsimulatedSimWafBodyLimits(resourceTypes: Iterable<string>): readonly SimWafUnsimulatedPart[];
@@ -0,0 +1,23 @@
1
+ /**
2
+ * The resource types a simulated request reaches a web ACL through.
3
+ */
4
+ const simulatedResourceTypes = new Set([
5
+ "CLOUDFRONT",
6
+ "API_GATEWAY",
7
+ "COGNITO_USER_POOL",
8
+ ]);
9
+ /**
10
+ * What the body inspection limits a web ACL sets leave out, one part per
11
+ * resource type no simulated request passes through.
12
+ */
13
+ export function unsimulatedSimWafBodyLimits(resourceTypes) {
14
+ return [...resourceTypes]
15
+ .filter((resourceType) => !simulatedResourceTypes.has(resourceType))
16
+ .map((resourceType) => ({
17
+ part: `AssociationConfig.RequestBody.${resourceType}`,
18
+ reason: `AssociationConfig sets the body inspection limit for ` +
19
+ `${resourceType} resources, and ` +
20
+ `${[...simulatedResourceTypes].join(" and ")} are the types a ` +
21
+ `simulated request reaches a web ACL through`,
22
+ }));
23
+ }
@@ -59,8 +59,8 @@ function nestedCapacity(statement) {
59
59
  *
60
60
  * A group is fixed at the capacity its owner gave it, and a scope-down
61
61
  * statement is charged on top. A group this simulation does not carry
62
- * contributes nothing, which cannot happen through a compiled web ACL: naming
63
- * one is refused where the rule is written.
62
+ * contributes nothing, so a web ACL holding one reports less than AWS would
63
+ * charge.
64
64
  */
65
65
  function managedGroupCapacity(statement) {
66
66
  const named = statement.ManagedRuleGroupStatement;
@@ -13,6 +13,11 @@ export interface SimWafWebAclConfiguration {
13
13
  readonly visibilityConfig?: unknown;
14
14
  readonly description?: string | undefined;
15
15
  readonly associationConfig?: SimWafAssociationConfigInput | undefined;
16
+ /**
17
+ * The members held as written and not acted on, such as `CaptchaConfig`,
18
+ * keyed by the name the API gives them.
19
+ */
20
+ readonly heldMembers?: Readonly<Record<string, unknown>> | undefined;
16
21
  }
17
22
  /**
18
23
  * Read the action a request no rule claims is given.
@@ -1,7 +1,7 @@
1
1
  import { type SimWafDecision } from "../evaluate/sim-waf-decision.js";
2
2
  import type { SimWafInspectedRequest } from "../evaluate/sim-waf-inspected-request.js";
3
3
  import { SimWafResource, type SimWafResourceProperties } from "../resource/sim-waf-resource.js";
4
- import { type SimWafBodyInspectionResourceType } from "./sim-waf-association-config.js";
4
+ import type { SimWafUnsimulatedPart } from "../resource/sim-waf-unsimulated-part.js";
5
5
  import type { SimWafWebAclRuleScope } from "./sim-waf-rule.type.js";
6
6
  import { type SimWafWebAclConfiguration } from "./sim-waf-web-acl-configuration.js";
7
7
  interface SimWafWebAclProperties extends SimWafResourceProperties, SimWafWebAclRuleScope {
@@ -33,6 +33,14 @@ export declare class SimWafWebAcl extends SimWafResource {
33
33
  * What this web ACL's rules add up to in capacity units.
34
34
  */
35
35
  get capacity(): number;
36
+ /**
37
+ * What this web ACL was written with and the simulation does not act on.
38
+ *
39
+ * A rule listed here claims no request, a member is held and does nothing,
40
+ * and a body inspection limit applies to no request. `GetWebACL` returns
41
+ * every one of them as written.
42
+ */
43
+ get unsimulated(): readonly SimWafUnsimulatedPart[];
36
44
  /**
37
45
  * What this web ACL was last written with, as the API reports it.
38
46
  */
@@ -42,6 +50,7 @@ export declare class SimWafWebAcl extends SimWafResource {
42
50
  *
43
51
  * The rules are compiled before anything is replaced, so a web ACL that
44
52
  * refuses an update keeps the rules it had rather than being left with none.
53
+ * The tags stay as they were created, since UpdateWebACL takes none.
45
54
  */
46
55
  reconfigure(configuration: SimWafWebAclConfiguration, lockToken: string | undefined): void;
47
56
  /**
@@ -51,7 +60,7 @@ export declare class SimWafWebAcl extends SimWafResource {
51
60
  * `AssociationConfig` raises it per resource type, and a web ACL written
52
61
  * without one reads the 16 KB default everything it protects has.
53
62
  */
54
- bodyInspectionLimitBytes(resourceType: SimWafBodyInspectionResourceType | undefined): number;
63
+ bodyInspectionLimitBytes(resourceType: string | undefined): number;
55
64
  /**
56
65
  * Decide what happens to one request.
57
66
  */
@@ -1,7 +1,8 @@
1
1
  import { simWafDecision, } from "../evaluate/sim-waf-decision.js";
2
2
  import { simWafEvaluateRules } from "../evaluate/sim-waf-evaluate-rules.js";
3
+ import { unsimulatedSimWafWebAclMembers } from "../command/web-acl/sim-wafv2-unsimulated-web-acl-input.js";
3
4
  import { SimWafResource, } from "../resource/sim-waf-resource.js";
4
- import { SimWafBodyInspectionLimits, } from "./sim-waf-association-config.js";
5
+ import { SimWafBodyInspectionLimits } from "./sim-waf-association-config.js";
5
6
  import { compileSimWafWebAclRules } from "./sim-waf-rules.js";
6
7
  import { simWafWebAclCapacity } from "./sim-waf-web-acl-capacity.js";
7
8
  import { readSimWafDefaultAction, } from "./sim-waf-web-acl-configuration.js";
@@ -49,6 +50,23 @@ export class SimWafWebAcl extends SimWafResource {
49
50
  get capacity() {
50
51
  return this.#capacity;
51
52
  }
53
+ /**
54
+ * What this web ACL was written with and the simulation does not act on.
55
+ *
56
+ * A rule listed here claims no request, a member is held and does nothing,
57
+ * and a body inspection limit applies to no request. `GetWebACL` returns
58
+ * every one of them as written.
59
+ */
60
+ get unsimulated() {
61
+ return [
62
+ ...this.#rules.flatMap(({ name, unsimulatedReason }) => unsimulatedReason === undefined
63
+ ? []
64
+ : [{ part: `Rules.${name}`, reason: unsimulatedReason }]),
65
+ ...unsimulatedSimWafWebAclMembers(this.#configuration.heldMembers ?? {}),
66
+ ...this.#bodyInspectionLimits.unsimulated,
67
+ ...super.unsimulated,
68
+ ];
69
+ }
52
70
  /**
53
71
  * What this web ACL was last written with, as the API reports it.
54
72
  */
@@ -60,6 +78,7 @@ export class SimWafWebAcl extends SimWafResource {
60
78
  *
61
79
  * The rules are compiled before anything is replaced, so a web ACL that
62
80
  * refuses an update keeps the rules it had rather than being left with none.
81
+ * The tags stay as they were created, since UpdateWebACL takes none.
63
82
  */
64
83
  reconfigure(configuration, lockToken) {
65
84
  const defaultAction = readSimWafDefaultAction(configuration);
@@ -486,7 +486,7 @@ Every ascending sort is emitted carrying `NULLS LAST`, because Trino orders null
486
486
  direction it sorts and SQLite orders them first ascending. Both were cases where a query answered
487
487
  differently while still succeeding, which is the failure that costs the most to find.
488
488
 
489
- ### Flattening an array or a map
489
+ ### Flattening an array, a map or a split value
490
490
 
491
491
  `UNNEST` runs. An array or a map column is held as its JSON text, and SQLite reads that with
492
492
  `json_each`, so a statement flattening one returns a row per element the way Athena does.
@@ -505,6 +505,22 @@ falls back rather than reading a scalar as a collection.
505
505
  One flattening per statement is what this covers, joined with `CROSS JOIN`. A second `UNNEST`, a
506
506
  `LEFT JOIN UNNEST`, a `SELECT *` beside one, and a position taken from a map all fall back.
507
507
 
508
+ A table with no array column in it can still be flattened. `split` answers an array, and an `UNNEST`
509
+ over the call cuts one stored string into a row per part. This is how a packed access log row is
510
+ read, since Glue builds a log table's columns from what the delivery was configured with.
511
+
512
+ ```sql
513
+ SELECT t.part
514
+ FROM rainlytics.logs
515
+ CROSS JOIN UNNEST(split(url_extract_parameter(cs_uri_stem || '?' || cs_uri_query, 'b'), ';'))
516
+ AS t(part)
517
+ ```
518
+
519
+ Splitting an empty value answers one empty part, as it does on Trino. A row whose value is null
520
+ answers no parts at all and drops out, the way an empty array column does. The call is what says the
521
+ value is a collection (an expression has no schema entry to read). `split` and `slice` are the two
522
+ calls the flattening reaches, and any other expression under an `UNNEST` falls back.
523
+
508
524
  ### The functions a statement can call
509
525
 
510
526
  SQLite carries a much smaller function library than Trino, and the engine fills the gap for the ones
@@ -516,7 +532,7 @@ its declared result.
516
532
  | Date and time | `current_date`, `current_timestamp`, `date_add`, `date_diff`, `date_trunc`, `date_format`, `at_timezone`, `from_unixtime`, `to_unixtime`, `from_iso8601_timestamp`, `from_iso8601_date`, `to_iso8601` |
517
533
  | JSON | `json_extract`, `json_extract_scalar`, `json_parse`, `json_size` |
518
534
  | Array and map | `array_agg`, `cardinality`, `contains`, `element_at`, `array_join`, `slice` |
519
- | String | `regexp_like`, `regexp_extract`, `regexp_replace`, `split_part`, `strpos` |
535
+ | String | `regexp_like`, `regexp_extract`, `regexp_replace`, `split`, `split_part`, `strpos` |
520
536
  | Binary | `md5`, `sha1`, `sha256`, `sha512`, `xxhash64`, `murmur3`, `crc32`, `to_hex`, `from_hex`, `to_base64`, `from_base64`, `to_utf8`, `from_utf8` |
521
537
  | URL | `url_extract_host`, `url_extract_path`, `url_extract_protocol`, `url_extract_port`, `url_extract_query`, `url_extract_fragment`, `url_extract_parameter`, `url_decode`, `url_encode` |
522
538
  | Approximate | `approx_distinct`, `approx_percentile` |
@@ -992,6 +1008,7 @@ own and authorizes work on one against the workgroup it belongs to. This asks th
992
1008
  - `StartQueryExecution`, `GetQueryExecution`, `GetQueryResults` and `StopQueryExecution`
993
1009
  - A `SELECT` run for real over JSON lines and CSV objects in simulated S3, answered by SQLite
994
1010
  - `UNNEST` over an array or a map column, with `WITH ORDINALITY` where a query wants the position
1011
+ - `UNNEST` over a `split` or a `slice` call, flattening one stored string into a row per part
995
1012
  - Trino's date, JSON, array, string and URL functions, with `current_timestamp` reading the
996
1013
  simulated clock
997
1014
  - Declared results, matched on the query text, ahead of the engine for one statement and behind it
@@ -1027,6 +1044,8 @@ Current documented limitations:
1027
1044
  gives a map's keys rather than its positions.
1028
1045
  - `UNNEST` over a `ROW` or a struct array falls back. The element needs field access and the
1029
1046
  flattened column is JSON text here.
1047
+ - `UNNEST` over an expression reaches `split` and `slice`. The engine reads the call to decide that
1048
+ a value is a collection, and a call to anything else falls back.
1030
1049
  - The Trino function library reaches as far as the table under
1031
1050
  [the functions a statement can call](#the-functions-a-statement-can-call). A query reaching for
1032
1051
  anything else Trino has and SQLite lacks falls back.