@kensio/yulin 1.21.23 → 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 (93) hide show
  1. package/dist/service/wafv2/association/sim-aws-waf-protected-resources.js +4 -0
  2. package/dist/service/wafv2/association/sim-waf-associations.d.ts +6 -0
  3. package/dist/service/wafv2/association/sim-waf-associations.js +17 -0
  4. package/dist/service/wafv2/association/sim-waf-protected-resource.d.ts +13 -8
  5. package/dist/service/wafv2/association/sim-waf-protected-resource.js +23 -23
  6. package/dist/service/wafv2/association/sim-waf-protected-resources.d.ts +11 -6
  7. package/dist/service/wafv2/association/sim-waf-protected-resources.js +10 -7
  8. package/dist/service/wafv2/association/sim-waf-unsimulated-resource.d.ts +33 -0
  9. package/dist/service/wafv2/association/sim-waf-unsimulated-resource.js +66 -0
  10. package/dist/service/wafv2/cfn/association/sim-cfn-waf-association-creator.js +5 -0
  11. package/dist/service/wafv2/cfn/ip-set/sim-cfn-waf-ip-set-config.js +1 -0
  12. package/dist/service/wafv2/cfn/ip-set/sim-cfn-waf-ip-set-creator.js +2 -0
  13. package/dist/service/wafv2/cfn/regex-pattern-set/sim-cfn-waf-regex-set-config.js +1 -0
  14. package/dist/service/wafv2/cfn/regex-pattern-set/sim-cfn-waf-regex-set-creator.js +2 -0
  15. package/dist/service/wafv2/cfn/sim-cfn-waf-resource-config.d.ts +4 -0
  16. package/dist/service/wafv2/cfn/sim-cfn-waf-resource-config.js +10 -0
  17. package/dist/service/wafv2/cfn/sim-cfn-waf-unsimulated.d.ts +10 -0
  18. package/dist/service/wafv2/cfn/sim-cfn-waf-unsimulated.js +12 -0
  19. package/dist/service/wafv2/cfn/web-acl/sim-cfn-waf-web-acl-config.d.ts +1 -13
  20. package/dist/service/wafv2/cfn/web-acl/sim-cfn-waf-web-acl-config.js +8 -21
  21. package/dist/service/wafv2/cfn/web-acl/sim-cfn-waf-web-acl-creator.d.ts +4 -9
  22. package/dist/service/wafv2/cfn/web-acl/sim-cfn-waf-web-acl-creator.js +7 -15
  23. package/dist/service/wafv2/command/association/sim-wafv2-association-commands.js +2 -1
  24. package/dist/service/wafv2/command/association/sim-wafv2-association-input.d.ts +10 -2
  25. package/dist/service/wafv2/command/association/sim-wafv2-association-input.js +25 -13
  26. package/dist/service/wafv2/command/ip-set/sim-wafv2-ip-set-commands.d.ts +3 -3
  27. package/dist/service/wafv2/command/ip-set/sim-wafv2-ip-set-commands.js +5 -5
  28. package/dist/service/wafv2/command/managed-rule-group/sim-wafv2-managed-rule-group-commands.js +4 -4
  29. package/dist/service/wafv2/command/regex-pattern-set/sim-wafv2-regex-pattern-set-commands.js +2 -2
  30. package/dist/service/wafv2/command/sim-wafv2-input.d.ts +0 -7
  31. package/dist/service/wafv2/command/sim-wafv2-input.js +1 -13
  32. package/dist/service/wafv2/command/web-acl/sim-waf-web-acl-output.js +1 -0
  33. package/dist/service/wafv2/command/web-acl/sim-wafv2-unsimulated-web-acl-input.d.ts +9 -12
  34. package/dist/service/wafv2/command/web-acl/sim-wafv2-unsimulated-web-acl-input.js +27 -28
  35. package/dist/service/wafv2/command/web-acl/sim-wafv2-web-acl-commands.d.ts +3 -3
  36. package/dist/service/wafv2/command/web-acl/sim-wafv2-web-acl-commands.js +6 -6
  37. package/dist/service/wafv2/command/web-acl/web-acl.command.d.ts +6 -0
  38. package/dist/service/wafv2/index.d.ts +3 -0
  39. package/dist/service/wafv2/index.js +1 -0
  40. package/dist/service/wafv2/managed/group/sim-waf-bot-control.d.ts +27 -0
  41. package/dist/service/wafv2/managed/group/sim-waf-bot-control.js +68 -0
  42. package/dist/service/wafv2/managed/group/sim-waf-ip-reputation.d.ts +18 -0
  43. package/dist/service/wafv2/managed/group/sim-waf-ip-reputation.js +51 -0
  44. package/dist/service/wafv2/managed/sim-waf-bot-declaration.d.ts +35 -0
  45. package/dist/service/wafv2/managed/sim-waf-bot-declaration.js +42 -0
  46. package/dist/service/wafv2/managed/sim-waf-managed-declaration.d.ts +35 -0
  47. package/dist/service/wafv2/managed/sim-waf-managed-declaration.js +30 -0
  48. package/dist/service/wafv2/managed/sim-waf-managed-group-configs.d.ts +11 -0
  49. package/dist/service/wafv2/managed/sim-waf-managed-group-configs.js +42 -0
  50. package/dist/service/wafv2/managed/sim-waf-managed-group-input.d.ts +5 -4
  51. package/dist/service/wafv2/managed/sim-waf-managed-group-input.js +7 -9
  52. package/dist/service/wafv2/managed/sim-waf-managed-group-statement.js +16 -14
  53. package/dist/service/wafv2/managed/sim-waf-managed-group.type.d.ts +2 -2
  54. package/dist/service/wafv2/managed/sim-waf-managed-rule-actions.d.ts +30 -0
  55. package/dist/service/wafv2/managed/sim-waf-managed-rule-actions.js +26 -0
  56. package/dist/service/wafv2/managed/sim-waf-managed-rule-groups.d.ts +5 -3
  57. package/dist/service/wafv2/managed/sim-waf-managed-rule-groups.js +10 -3
  58. package/dist/service/wafv2/managed/sim-waf-managed-rule.type.d.ts +11 -2
  59. package/dist/service/wafv2/managed/sim-waf-managed-rules.d.ts +14 -9
  60. package/dist/service/wafv2/managed/sim-waf-managed-rules.js +15 -5
  61. package/dist/service/wafv2/resource/sim-waf-resource.d.ts +10 -0
  62. package/dist/service/wafv2/resource/sim-waf-resource.js +12 -0
  63. package/dist/service/wafv2/resource/sim-waf-unsimulated-part.d.ts +24 -0
  64. package/dist/service/wafv2/resource/sim-waf-unsimulated-part.js +8 -0
  65. package/dist/service/wafv2/sim-wafv2.d.ts +12 -12
  66. package/dist/service/wafv2/sim-wafv2.fixture.d.ts +19 -1
  67. package/dist/service/wafv2/sim-wafv2.fixture.js +29 -0
  68. package/dist/service/wafv2/sim-wafv2.js +25 -23
  69. package/dist/service/wafv2/statement/sim-waf-field-to-match.type.d.ts +2 -2
  70. package/dist/service/wafv2/statement/sim-waf-rule-refusals.d.ts +6 -4
  71. package/dist/service/wafv2/statement/sim-waf-rule-refusals.js +7 -6
  72. package/dist/service/wafv2/statement/sim-waf-statement.d.ts +3 -3
  73. package/dist/service/wafv2/statement/sim-waf-statement.js +3 -3
  74. package/dist/service/wafv2/statement/sim-waf-statement.type.d.ts +3 -3
  75. package/dist/service/wafv2/statement/sim-waf-unsimulated-statement.js +1 -1
  76. package/dist/service/wafv2/web-acl/sim-waf-association-config.d.ts +14 -7
  77. package/dist/service/wafv2/web-acl/sim-waf-association-config.js +17 -27
  78. package/dist/service/wafv2/web-acl/sim-waf-rule.d.ts +15 -3
  79. package/dist/service/wafv2/web-acl/sim-waf-rule.js +46 -10
  80. package/dist/service/wafv2/web-acl/sim-waf-statement-capacity.d.ts +4 -4
  81. package/dist/service/wafv2/web-acl/sim-waf-statement-capacity.js +4 -4
  82. package/dist/service/wafv2/web-acl/sim-waf-unsimulated-body-limit.d.ts +6 -0
  83. package/dist/service/wafv2/web-acl/sim-waf-unsimulated-body-limit.js +23 -0
  84. package/dist/service/wafv2/web-acl/sim-waf-web-acl-capacity.js +2 -2
  85. package/dist/service/wafv2/web-acl/sim-waf-web-acl-configuration.d.ts +5 -0
  86. package/dist/service/wafv2/web-acl/sim-waf-web-acl.d.ts +11 -2
  87. package/dist/service/wafv2/web-acl/sim-waf-web-acl.js +20 -1
  88. package/docs/services/wafv2/README.md +243 -51
  89. package/package.json +2 -2
  90. package/dist/service/wafv2/cfn/web-acl/sim-cfn-waf-evaluatable-rules.d.ts +0 -15
  91. package/dist/service/wafv2/cfn/web-acl/sim-cfn-waf-evaluatable-rules.js +0 -21
  92. package/dist/service/wafv2/web-acl/sim-waf-unevaluatable-rules.d.ts +0 -25
  93. package/dist/service/wafv2/web-acl/sim-waf-unevaluatable-rules.js +0 -33
@@ -0,0 +1,24 @@
1
+ /**
2
+ * One part of a WAFv2 write this simulation holds and does not act on.
3
+ *
4
+ * A write carrying something Yulin does not simulate is accepted, and the read
5
+ * that follows returns it as written. What the simulation leaves out is
6
+ * reported here instead, so a test can find out how far the resource it wrote
7
+ * is from the one AWS would run.
8
+ */
9
+ export interface SimWafUnsimulatedPart {
10
+ /**
11
+ * Where the part sits in what was written.
12
+ *
13
+ * A rule is `Rules.<rule name>`, a web ACL member is its own name, and a body
14
+ * inspection limit is `AssociationConfig.RequestBody.<resource type>`. These
15
+ * are the names a CloudFormation Resource records them under.
16
+ */
17
+ readonly part: string;
18
+ /** Why the simulation does not act on it. */
19
+ readonly reason: string;
20
+ }
21
+ /**
22
+ * What a resource's tags leave out, which is nothing when it has none.
23
+ */
24
+ export declare function simWafTagsParts(tags: readonly unknown[]): readonly SimWafUnsimulatedPart[];
@@ -0,0 +1,8 @@
1
+ const tagsReason = "the tags are held and nothing reads them, since ListTagsForResource is " +
2
+ "not simulated";
3
+ /**
4
+ * What a resource's tags leave out, which is nothing when it has none.
5
+ */
6
+ export function simWafTagsParts(tags) {
7
+ return tags.length === 0 ? [] : [{ part: "Tags", reason: tagsReason }];
8
+ }
@@ -8,12 +8,11 @@ import type { SimWafIpSet } from "./ip-set/sim-waf-ip-set.js";
8
8
  import type { SimWafManagedRules } from "./managed/sim-waf-managed-rules.js";
9
9
  import type { SimWafRegexPatternSet } from "./regex-pattern-set/sim-waf-regex-pattern-set.js";
10
10
  import type { SimWafScope } from "./scope/sim-waf-scope.js";
11
+ import type { SimWafUnsimulatedPart } from "./resource/sim-waf-unsimulated-part.js";
11
12
  import { type SimWafV2Properties } from "./sim-wafv2-commands.js";
12
13
  import { SimWafCfnResourceFactory } from "./cfn/sim-waf-cfn-resource-factory.js";
13
14
  import { SimWafSets } from "./sim-wafv2-sets.js";
14
15
  import type { SimWafWebAcl } from "./web-acl/sim-waf-web-acl.js";
15
- import { type SimWafUnevaluatableRule } from "./web-acl/sim-waf-unevaluatable-rules.js";
16
- import type { SimWafWebAclWriteInput } from "./command/web-acl/web-acl.command.js";
17
16
  export type { SimWafEvaluationRequest } from "./evaluate/sim-waf-evaluation-request.js";
18
17
  /**
19
18
  * Simulated AWS WAFv2. Handles SDK commands. Emulates AWS behaviour and state.
@@ -71,6 +70,13 @@ export declare class SimWafV2 extends SimWafSets {
71
70
  * compiled against, since a reference carries the ARN and nothing else.
72
71
  */
73
72
  findRegexPatternSetByArn(regexPatternSetArn: string): SimWafRegexPatternSet | undefined;
73
+ /**
74
+ * What a web ACL holds and this simulation does not act on, each part with
75
+ * its reason: a rule that claims no request (`Rules.<rule name>`), a member
76
+ * such as `CaptchaConfig`, a body inspection limit, the tags, and an
77
+ * association nothing is evaluated through (`Association.<resource ARN>`).
78
+ */
79
+ unsimulatedParts(webAclArn: string): readonly SimWafUnsimulatedPart[];
74
80
  /**
75
81
  * Evaluate one HTTP request against a web ACL's rules.
76
82
  *
@@ -89,16 +95,6 @@ export declare class SimWafV2 extends SimWafSets {
89
95
  * nothing here, and `rules()` reports what is covered of each.
90
96
  */
91
97
  managedRules(): SimWafManagedRules;
92
- /**
93
- * The rules of a web ACL input this simulation cannot evaluate.
94
- *
95
- * The simulator's own accessor rather than a WAFv2 operation. `CreateWebACL`
96
- * refuses a web ACL carrying such a rule, because a web ACL that accepted
97
- * one would allow a request AWS blocks. A template is deployed rule by rule
98
- * instead, so the CloudFormation layer asks this first and leaves the rules
99
- * it names out of the web ACL it writes.
100
- */
101
- unevaluatableWebAclRules(input: SimWafWebAclWriteInput): readonly SimWafUnevaluatableRule[];
102
98
  /**
103
99
  * Handle a CreateWebACL Command from the SDK.
104
100
  */
@@ -147,4 +143,8 @@ export declare class SimWafV2 extends SimWafSets {
147
143
  * Get this service's SDK Command router for SDK client interception.
148
144
  */
149
145
  sdkCommandRouter(): SimSdkCommandRouter;
146
+ /**
147
+ * Find a web ACL by its ARN, refusing one that is not here.
148
+ */
149
+ private requireWebAcl;
150
150
  }
@@ -1,5 +1,6 @@
1
- import type { SimCreateWebAclCommandInput, SimWafSummaryOutput } from "./command/web-acl/web-acl.command.js";
1
+ import type { SimCreateWebAclCommandInput, SimWafSummaryOutput, SimWafWebAclOutput } from "./command/web-acl/web-acl.command.js";
2
2
  import type { SimWafDecision } from "./evaluate/sim-waf-decision.js";
3
+ import type { SimWafUnsimulatedPart } from "./resource/sim-waf-unsimulated-part.js";
3
4
  import type { SimWafStatementInput } from "./statement/sim-waf-statement.type.js";
4
5
  import type { SimWafRuleInput } from "./web-acl/sim-waf-rule.type.js";
5
6
  import type { SimWafV2 } from "./sim-wafv2.js";
@@ -47,3 +48,20 @@ export declare function simWafWebAclDecisions(simWaf: SimWafV2, rules: readonly
47
48
  * makes its requests with this.
48
49
  */
49
50
  export declare function simWafBrowserRequest(url: string, init?: RequestInit): Request;
51
+ /**
52
+ * A web ACL as GetWebACL reads it back, what the simulation says it left out
53
+ * of it, and what it decided about an ordinary request.
54
+ */
55
+ export interface SimWafHeld {
56
+ readonly webAcl: SimWafWebAclOutput;
57
+ readonly parts: readonly SimWafUnsimulatedPart[];
58
+ readonly blocked: boolean;
59
+ }
60
+ /**
61
+ * Create a web ACL, read it back, and put one request through it.
62
+ */
63
+ export declare function simWafHeldWebAcl(simWaf: SimWafV2, webAcl: Partial<SimCreateWebAclCommandInput>): Promise<SimWafHeld>;
64
+ /**
65
+ * The reason the simulation gives for leaving out one part.
66
+ */
67
+ export declare function simWafUnsimulatedReason(parts: readonly SimWafUnsimulatedPart[], part: string): string;
@@ -60,3 +60,32 @@ export function simWafBrowserRequest(url, init = {}) {
60
60
  return new Request(url, { ...init, headers });
61
61
  }
62
62
  const browserUserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36";
63
+ /**
64
+ * Create a web ACL, read it back, and put one request through it.
65
+ */
66
+ export async function simWafHeldWebAcl(simWaf, webAcl) {
67
+ const created = await createSimWafWebAcl(simWaf, {
68
+ ...simWafCreateWebAclFactory.make(),
69
+ ...webAcl,
70
+ });
71
+ const read = await simWaf.getWebAcl({
72
+ input: { Name: created.Name, Scope: "REGIONAL", Id: created.Id },
73
+ });
74
+ assertDefined(read.WebACL, "Simulated WAFv2 read back no web ACL");
75
+ return {
76
+ webAcl: read.WebACL,
77
+ parts: simWaf.unsimulatedParts(created.ARN),
78
+ blocked: simWaf.evaluateRequest({
79
+ webAclArn: created.ARN,
80
+ request: new Request("https://example.com/search"),
81
+ }).action === "BLOCK",
82
+ };
83
+ }
84
+ /**
85
+ * The reason the simulation gives for leaving out one part.
86
+ */
87
+ export function simWafUnsimulatedReason(parts, part) {
88
+ const found = parts.find((candidate) => candidate.part === part);
89
+ assertDefined(found, `Simulated WAFv2 reported no unsimulated part ${part}`);
90
+ return found.reason;
91
+ }
@@ -4,7 +4,6 @@ import { SimWafSdkCommandRouter } from "./sdk/sim-wafv2-sdk-command-router.js";
4
4
  import { SimWafCommands, } from "./sim-wafv2-commands.js";
5
5
  import { SimWafCfnResourceFactory } from "./cfn/sim-waf-cfn-resource-factory.js";
6
6
  import { SimWafSets } from "./sim-wafv2-sets.js";
7
- import { unevaluatableSimWafRules, } from "./web-acl/sim-waf-unevaluatable-rules.js";
8
7
  /**
9
8
  * Simulated AWS WAFv2. Handles SDK commands. Emulates AWS behaviour and state.
10
9
  *
@@ -74,6 +73,19 @@ export class SimWafV2 extends SimWafSets {
74
73
  findRegexPatternSetByArn(regexPatternSetArn) {
75
74
  return this.commands.regexPatternSets.findByArn(regexPatternSetArn);
76
75
  }
76
+ /**
77
+ * What a web ACL holds and this simulation does not act on, each part with
78
+ * its reason: a rule that claims no request (`Rules.<rule name>`), a member
79
+ * such as `CaptchaConfig`, a body inspection limit, the tags, and an
80
+ * association nothing is evaluated through (`Association.<resource ARN>`).
81
+ */
82
+ unsimulatedParts(webAclArn) {
83
+ const webAcl = this.requireWebAcl(webAclArn);
84
+ return [
85
+ ...webAcl.unsimulated,
86
+ ...this.commands.associations.unsimulatedFor(webAcl),
87
+ ];
88
+ }
77
89
  /**
78
90
  * Evaluate one HTTP request against a web ACL's rules.
79
91
  *
@@ -84,11 +96,7 @@ export class SimWafV2 extends SimWafSets {
84
96
  * front of.
85
97
  */
86
98
  evaluateRequest(evaluation) {
87
- const webAcl = this.findWebAclByArn(evaluation.webAclArn);
88
- if (webAcl === undefined) {
89
- throw new SimWafNonexistentItemException(`AWS WAF couldn't perform the operation because your resource ` +
90
- `doesn't exist: web ACL ${evaluation.webAclArn}.`);
91
- }
99
+ const webAcl = this.requireWebAcl(evaluation.webAclArn);
92
100
  const limitBytes = webAcl.bodyInspectionLimitBytes(evaluation.resourceType);
93
101
  return webAcl.evaluate(simWafInspectedRequest(evaluation.request, evaluation.body, limitBytes));
94
102
  }
@@ -102,23 +110,6 @@ export class SimWafV2 extends SimWafSets {
102
110
  managedRules() {
103
111
  return this.commands.managedRules;
104
112
  }
105
- /**
106
- * The rules of a web ACL input this simulation cannot evaluate.
107
- *
108
- * The simulator's own accessor rather than a WAFv2 operation. `CreateWebACL`
109
- * refuses a web ACL carrying such a rule, because a web ACL that accepted
110
- * one would allow a request AWS blocks. A template is deployed rule by rule
111
- * instead, so the CloudFormation layer asks this first and leaves the rules
112
- * it names out of the web ACL it writes.
113
- */
114
- unevaluatableWebAclRules(input) {
115
- return unevaluatableSimWafRules(input.Rules, {
116
- regexPatternSets: this.commands.regexPatternSets,
117
- managedRules: this.commands.managedRules,
118
- clock: this.commands.background,
119
- customResponseBodies: input.CustomResponseBodies ?? {},
120
- });
121
- }
122
113
  /**
123
114
  * Handle a CreateWebACL Command from the SDK.
124
115
  */
@@ -201,4 +192,15 @@ export class SimWafV2 extends SimWafSets {
201
192
  sdkCommandRouter() {
202
193
  return this.#sdkRouter;
203
194
  }
195
+ /**
196
+ * Find a web ACL by its ARN, refusing one that is not here.
197
+ */
198
+ requireWebAcl(webAclArn) {
199
+ const webAcl = this.findWebAclByArn(webAclArn);
200
+ if (webAcl === undefined) {
201
+ throw new SimWafNonexistentItemException(`AWS WAF couldn't perform the operation because your resource ` +
202
+ `doesn't exist: web ACL ${webAclArn}.`);
203
+ }
204
+ return webAcl;
205
+ }
204
206
  }
@@ -4,8 +4,8 @@ import type { SimWafMatchPatternInput } from "./sim-waf-match-pattern.js";
4
4
  * shape.
5
5
  *
6
6
  * The members Yulin does not simulate are declared here rather than left out,
7
- * so a rule that names one is refused by name instead of being read as a rule
8
- * with no field at all.
7
+ * so a rule that names one is held and reported by name instead of being read
8
+ * as a rule with no field at all.
9
9
  */
10
10
  export interface SimWafFieldToMatchInput {
11
11
  readonly UriPath?: unknown;
@@ -1,10 +1,12 @@
1
1
  /**
2
- * Refuse something in a rule that real WAFv2 takes and this simulation does
2
+ * Stop compiling a rule at something real WAFv2 takes and this simulation does
3
3
  * not.
4
4
  *
5
- * Every refusal names the rule and what in it was refused, because a web ACL
6
- * is a list of rules that all look alike from the outside and the name is the
7
- * only thing that says which one to go and look at.
5
+ * `SimWafRule.compile` catches it and holds the rule unevaluated, with this
6
+ * message as the reason the web ACL reports. The message names the rule and
7
+ * what in it was left out, because a web ACL is a list of rules that all look
8
+ * alike from the outside and the name is the only thing that says which one to
9
+ * go and look at.
8
10
  */
9
11
  export declare function refuseSimWafRuleInput(ruleName: string, refused: string, reason: string): never;
10
12
  /**
@@ -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
+ }