@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.
- package/dist/service/athena/engine/sim-athena-ast-nodes.d.ts +11 -0
- package/dist/service/athena/engine/sim-athena-ast-nodes.js +22 -0
- package/dist/service/athena/engine/sim-athena-string-shims.js +29 -1
- package/dist/service/athena/engine/sim-athena-unnest-item.js +6 -15
- package/dist/service/athena/engine/sim-athena-unnest-rewrite.d.ts +4 -4
- package/dist/service/athena/engine/sim-athena-unnest-rewrite.js +4 -4
- package/dist/service/athena/engine/sim-athena-unnest-source.d.ts +10 -9
- package/dist/service/athena/engine/sim-athena-unnest-source.js +25 -11
- package/dist/service/athena/sim-athena-flattened-events.fixture.d.ts +3 -0
- package/dist/service/athena/sim-athena-flattened-events.fixture.js +46 -0
- package/dist/service/wafv2/association/sim-aws-waf-protected-resources.js +4 -0
- package/dist/service/wafv2/association/sim-waf-associations.d.ts +6 -0
- package/dist/service/wafv2/association/sim-waf-associations.js +17 -0
- package/dist/service/wafv2/association/sim-waf-protected-resource.d.ts +13 -8
- package/dist/service/wafv2/association/sim-waf-protected-resource.js +23 -23
- package/dist/service/wafv2/association/sim-waf-protected-resources.d.ts +11 -6
- package/dist/service/wafv2/association/sim-waf-protected-resources.js +10 -7
- package/dist/service/wafv2/association/sim-waf-unsimulated-resource.d.ts +33 -0
- package/dist/service/wafv2/association/sim-waf-unsimulated-resource.js +66 -0
- package/dist/service/wafv2/cfn/association/sim-cfn-waf-association-creator.js +5 -0
- package/dist/service/wafv2/cfn/ip-set/sim-cfn-waf-ip-set-config.js +1 -0
- package/dist/service/wafv2/cfn/ip-set/sim-cfn-waf-ip-set-creator.js +2 -0
- package/dist/service/wafv2/cfn/regex-pattern-set/sim-cfn-waf-regex-set-config.js +1 -0
- package/dist/service/wafv2/cfn/regex-pattern-set/sim-cfn-waf-regex-set-creator.js +2 -0
- package/dist/service/wafv2/cfn/sim-cfn-waf-resource-config.d.ts +4 -0
- package/dist/service/wafv2/cfn/sim-cfn-waf-resource-config.js +10 -0
- package/dist/service/wafv2/cfn/sim-cfn-waf-unsimulated.d.ts +10 -0
- package/dist/service/wafv2/cfn/sim-cfn-waf-unsimulated.js +12 -0
- package/dist/service/wafv2/cfn/web-acl/sim-cfn-waf-web-acl-config.d.ts +1 -13
- package/dist/service/wafv2/cfn/web-acl/sim-cfn-waf-web-acl-config.js +8 -21
- package/dist/service/wafv2/cfn/web-acl/sim-cfn-waf-web-acl-creator.d.ts +4 -9
- package/dist/service/wafv2/cfn/web-acl/sim-cfn-waf-web-acl-creator.js +7 -15
- package/dist/service/wafv2/command/association/sim-wafv2-association-commands.js +2 -1
- package/dist/service/wafv2/command/association/sim-wafv2-association-input.d.ts +10 -2
- package/dist/service/wafv2/command/association/sim-wafv2-association-input.js +25 -13
- package/dist/service/wafv2/command/ip-set/sim-wafv2-ip-set-commands.d.ts +3 -3
- package/dist/service/wafv2/command/ip-set/sim-wafv2-ip-set-commands.js +5 -5
- package/dist/service/wafv2/command/managed-rule-group/sim-wafv2-managed-rule-group-commands.js +4 -4
- package/dist/service/wafv2/command/regex-pattern-set/sim-wafv2-regex-pattern-set-commands.js +2 -2
- package/dist/service/wafv2/command/sim-wafv2-input.d.ts +0 -7
- package/dist/service/wafv2/command/sim-wafv2-input.js +1 -13
- package/dist/service/wafv2/command/web-acl/sim-waf-web-acl-output.js +1 -0
- package/dist/service/wafv2/command/web-acl/sim-wafv2-unsimulated-web-acl-input.d.ts +9 -12
- package/dist/service/wafv2/command/web-acl/sim-wafv2-unsimulated-web-acl-input.js +27 -28
- package/dist/service/wafv2/command/web-acl/sim-wafv2-web-acl-commands.d.ts +3 -3
- package/dist/service/wafv2/command/web-acl/sim-wafv2-web-acl-commands.js +6 -6
- package/dist/service/wafv2/command/web-acl/web-acl.command.d.ts +6 -0
- package/dist/service/wafv2/index.d.ts +3 -0
- package/dist/service/wafv2/index.js +1 -0
- package/dist/service/wafv2/managed/group/sim-waf-bot-control.d.ts +27 -0
- package/dist/service/wafv2/managed/group/sim-waf-bot-control.js +68 -0
- package/dist/service/wafv2/managed/group/sim-waf-ip-reputation.d.ts +18 -0
- package/dist/service/wafv2/managed/group/sim-waf-ip-reputation.js +51 -0
- package/dist/service/wafv2/managed/sim-waf-bot-declaration.d.ts +35 -0
- package/dist/service/wafv2/managed/sim-waf-bot-declaration.js +42 -0
- package/dist/service/wafv2/managed/sim-waf-managed-declaration.d.ts +35 -0
- package/dist/service/wafv2/managed/sim-waf-managed-declaration.js +30 -0
- package/dist/service/wafv2/managed/sim-waf-managed-group-configs.d.ts +11 -0
- package/dist/service/wafv2/managed/sim-waf-managed-group-configs.js +42 -0
- package/dist/service/wafv2/managed/sim-waf-managed-group-input.d.ts +5 -4
- package/dist/service/wafv2/managed/sim-waf-managed-group-input.js +7 -9
- package/dist/service/wafv2/managed/sim-waf-managed-group-statement.js +16 -14
- package/dist/service/wafv2/managed/sim-waf-managed-group.type.d.ts +2 -2
- package/dist/service/wafv2/managed/sim-waf-managed-rule-actions.d.ts +30 -0
- package/dist/service/wafv2/managed/sim-waf-managed-rule-actions.js +26 -0
- package/dist/service/wafv2/managed/sim-waf-managed-rule-groups.d.ts +5 -3
- package/dist/service/wafv2/managed/sim-waf-managed-rule-groups.js +10 -3
- package/dist/service/wafv2/managed/sim-waf-managed-rule.type.d.ts +11 -2
- package/dist/service/wafv2/managed/sim-waf-managed-rules.d.ts +14 -9
- package/dist/service/wafv2/managed/sim-waf-managed-rules.js +15 -5
- package/dist/service/wafv2/resource/sim-waf-resource.d.ts +10 -0
- package/dist/service/wafv2/resource/sim-waf-resource.js +12 -0
- package/dist/service/wafv2/resource/sim-waf-unsimulated-part.d.ts +24 -0
- package/dist/service/wafv2/resource/sim-waf-unsimulated-part.js +8 -0
- package/dist/service/wafv2/sim-wafv2.d.ts +12 -12
- package/dist/service/wafv2/sim-wafv2.fixture.d.ts +19 -1
- package/dist/service/wafv2/sim-wafv2.fixture.js +29 -0
- package/dist/service/wafv2/sim-wafv2.js +25 -23
- package/dist/service/wafv2/statement/sim-waf-field-to-match.type.d.ts +2 -2
- package/dist/service/wafv2/statement/sim-waf-rule-refusals.d.ts +6 -4
- package/dist/service/wafv2/statement/sim-waf-rule-refusals.js +7 -6
- package/dist/service/wafv2/statement/sim-waf-statement.d.ts +3 -3
- package/dist/service/wafv2/statement/sim-waf-statement.js +3 -3
- package/dist/service/wafv2/statement/sim-waf-statement.type.d.ts +3 -3
- package/dist/service/wafv2/statement/sim-waf-unsimulated-statement.js +1 -1
- package/dist/service/wafv2/web-acl/sim-waf-association-config.d.ts +14 -7
- package/dist/service/wafv2/web-acl/sim-waf-association-config.js +17 -27
- package/dist/service/wafv2/web-acl/sim-waf-rule.d.ts +15 -3
- package/dist/service/wafv2/web-acl/sim-waf-rule.js +46 -10
- package/dist/service/wafv2/web-acl/sim-waf-statement-capacity.d.ts +4 -4
- package/dist/service/wafv2/web-acl/sim-waf-statement-capacity.js +4 -4
- package/dist/service/wafv2/web-acl/sim-waf-unsimulated-body-limit.d.ts +6 -0
- package/dist/service/wafv2/web-acl/sim-waf-unsimulated-body-limit.js +23 -0
- package/dist/service/wafv2/web-acl/sim-waf-web-acl-capacity.js +2 -2
- package/dist/service/wafv2/web-acl/sim-waf-web-acl-configuration.d.ts +5 -0
- package/dist/service/wafv2/web-acl/sim-waf-web-acl.d.ts +11 -2
- package/dist/service/wafv2/web-acl/sim-waf-web-acl.js +20 -1
- package/docs/services/athena/README.md +21 -2
- package/docs/services/wafv2/README.md +243 -51
- package/package.json +2 -2
- package/dist/service/wafv2/cfn/web-acl/sim-cfn-waf-evaluatable-rules.d.ts +0 -15
- package/dist/service/wafv2/cfn/web-acl/sim-cfn-waf-evaluatable-rules.js +0 -21
- package/dist/service/wafv2/web-acl/sim-waf-unevaluatable-rules.d.ts +0 -25
- package/dist/service/wafv2/web-acl/sim-waf-unevaluatable-rules.js +0 -33
|
@@ -18,6 +18,17 @@ export interface SimAthenaFromItem extends SimAthenaAstNode {
|
|
|
18
18
|
table: string;
|
|
19
19
|
as?: string | null;
|
|
20
20
|
}
|
|
21
|
+
/** One value as a node, or nothing where it is not an object. */
|
|
22
|
+
export declare function asAstNode(value: unknown): SimAthenaAstNode | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* The name a call carries, where the statement wrote it as one part.
|
|
25
|
+
*
|
|
26
|
+
* The parser holds a name as a list, one entry per piece of a qualified name,
|
|
27
|
+
* and it holds an `UNNEST` alias as a call of its own. A name written in more
|
|
28
|
+
* than one part answers with nothing, since neither the engine's functions nor
|
|
29
|
+
* an alias is reached that way.
|
|
30
|
+
*/
|
|
31
|
+
export declare function simAthenaCalledName(node: SimAthenaAstNode | undefined): string | undefined;
|
|
21
32
|
/** Every node in the tree, the outermost first. */
|
|
22
33
|
export declare function simAthenaAstNodes(root: unknown): Generator<SimAthenaAstNode>;
|
|
23
34
|
/** Whether this node references a column. */
|
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
/** One value as a node, or nothing where it is not an object. */
|
|
2
|
+
export function asAstNode(value) {
|
|
3
|
+
return typeof value === "object" && value !== null
|
|
4
|
+
? value
|
|
5
|
+
: undefined;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The name a call carries, where the statement wrote it as one part.
|
|
9
|
+
*
|
|
10
|
+
* The parser holds a name as a list, one entry per piece of a qualified name,
|
|
11
|
+
* and it holds an `UNNEST` alias as a call of its own. A name written in more
|
|
12
|
+
* than one part answers with nothing, since neither the engine's functions nor
|
|
13
|
+
* an alias is reached that way.
|
|
14
|
+
*/
|
|
15
|
+
export function simAthenaCalledName(node) {
|
|
16
|
+
const parts = asAstNode(node?.["name"])?.["name"];
|
|
17
|
+
const first = Array.isArray(parts) && parts.length === 1
|
|
18
|
+
? asAstNode(parts[0])
|
|
19
|
+
: undefined;
|
|
20
|
+
const name = first?.["value"];
|
|
21
|
+
return typeof name === "string" ? name : undefined;
|
|
22
|
+
}
|
|
1
23
|
/** Every node in the tree, the outermost first. */
|
|
2
24
|
export function* simAthenaAstNodes(root) {
|
|
3
25
|
if (Array.isArray(root)) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SimAthenaSetUpError } from "../error/sim-athena.error.js";
|
|
2
|
+
import { isExplicitNull, shimNumber, shimText, simAthenaScalarShim, } from "./sim-athena-shim-registry.js";
|
|
2
3
|
/**
|
|
3
4
|
* Trino's string functions.
|
|
4
5
|
*
|
|
@@ -8,9 +9,36 @@ import { shimNumber, shimText, simAthenaScalarShim, } from "./sim-athena-shim-re
|
|
|
8
9
|
* with something that works less well.
|
|
9
10
|
*/
|
|
10
11
|
export function simAthenaInstallStringShims(database) {
|
|
12
|
+
simAthenaScalarShim(database, "split", (...values) => isExplicitNull(values, 2)
|
|
13
|
+
? null
|
|
14
|
+
: split(shimText(values.at(0)), shimText(values.at(1)), shimNumber(values.at(2))));
|
|
11
15
|
simAthenaScalarShim(database, "split_part", (value, delimiter, index) => splitPart(shimText(value), shimText(delimiter), shimNumber(index)));
|
|
12
16
|
simAthenaScalarShim(database, "strpos", (value, search) => position(shimText(value), shimText(search)));
|
|
13
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* One value cut into an array, written as the JSON text an array is held as.
|
|
20
|
+
*
|
|
21
|
+
* Trino answers with one empty element over an empty value, and refuses an
|
|
22
|
+
* empty delimiter rather than answering a character at a time. A limit caps
|
|
23
|
+
* how many elements come back and leaves the rest of the value in the last of
|
|
24
|
+
* them.
|
|
25
|
+
*/
|
|
26
|
+
function split(value, delimiter, limit) {
|
|
27
|
+
if (value === undefined || delimiter === undefined) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
if (delimiter === "" || (limit !== undefined && limit < 1)) {
|
|
31
|
+
throw new SimAthenaSetUpError("split takes a delimiter of at least one character and a limit from one");
|
|
32
|
+
}
|
|
33
|
+
const parts = value.split(delimiter);
|
|
34
|
+
if (limit === undefined || parts.length <= limit) {
|
|
35
|
+
return JSON.stringify(parts);
|
|
36
|
+
}
|
|
37
|
+
return JSON.stringify([
|
|
38
|
+
...parts.slice(0, limit - 1),
|
|
39
|
+
parts.slice(limit - 1).join(delimiter),
|
|
40
|
+
]);
|
|
41
|
+
}
|
|
14
42
|
/** Trino counts the fields from one, and has no field below that. */
|
|
15
43
|
function splitPart(value, delimiter, index) {
|
|
16
44
|
if (value === undefined || delimiter === undefined || index === undefined) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { simAthenaAstNodes, } from "./sim-athena-ast-nodes.js";
|
|
1
|
+
import { asAstNode, simAthenaAstNodes, simAthenaCalledName, } from "./sim-athena-ast-nodes.js";
|
|
2
2
|
/**
|
|
3
3
|
* The `UNNEST` a statement flattens an array or a map with.
|
|
4
4
|
*
|
|
@@ -19,8 +19,8 @@ export function simAthenaUnnestItem(ast) {
|
|
|
19
19
|
}
|
|
20
20
|
const alias = aliasOf(item);
|
|
21
21
|
const columns = aliasColumns(item);
|
|
22
|
-
const source = item["expr"];
|
|
23
|
-
if (alias === undefined || columns === undefined ||
|
|
22
|
+
const source = asAstNode(item["expr"]);
|
|
23
|
+
if (alias === undefined || columns === undefined || source === undefined) {
|
|
24
24
|
return { kind: "unreadable" };
|
|
25
25
|
}
|
|
26
26
|
return { kind: "found", item, alias, columns, source };
|
|
@@ -38,25 +38,16 @@ function isCrossJoined(item) {
|
|
|
38
38
|
}
|
|
39
39
|
/** The alias name, which the parser holds as a function's name. */
|
|
40
40
|
function aliasOf(item) {
|
|
41
|
-
|
|
42
|
-
const first = Array.isArray(parts) ? asNode(parts[0]) : undefined;
|
|
43
|
-
const value = first?.["value"];
|
|
44
|
-
return typeof value === "string" ? value : undefined;
|
|
41
|
+
return simAthenaCalledName(asAstNode(item["as"]));
|
|
45
42
|
}
|
|
46
43
|
/** The names inside the alias, which the parser holds as a function's arguments. */
|
|
47
44
|
function aliasColumns(item) {
|
|
48
|
-
const values =
|
|
45
|
+
const values = asAstNode(asAstNode(item["as"])?.["args"])?.["value"];
|
|
49
46
|
if (!Array.isArray(values) || values.length === 0) {
|
|
50
47
|
return undefined;
|
|
51
48
|
}
|
|
52
|
-
const columns = values.map((value) =>
|
|
49
|
+
const columns = values.map((value) => asAstNode(value)?.["column"]);
|
|
53
50
|
return columns.every((column) => typeof column === "string")
|
|
54
51
|
? columns
|
|
55
52
|
: undefined;
|
|
56
53
|
}
|
|
57
|
-
function isNode(value) {
|
|
58
|
-
return typeof value === "object" && value !== null;
|
|
59
|
-
}
|
|
60
|
-
function asNode(value) {
|
|
61
|
-
return isNode(value) ? value : undefined;
|
|
62
|
-
}
|
|
@@ -7,10 +7,10 @@ interface SimAthenaUnnestRewriteRequest {
|
|
|
7
7
|
/**
|
|
8
8
|
* Turn an `UNNEST` into the `json_each` SQLite flattens JSON with.
|
|
9
9
|
*
|
|
10
|
-
* An array or a map column is held as its JSON text,
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* answers with.
|
|
10
|
+
* An array or a map column is held as its JSON text, as is what a function like
|
|
11
|
+
* `split` answers, and `json_each` reads that as one row per element with a
|
|
12
|
+
* `key` and a `value`. The `FROM` entry becomes a call to it and every
|
|
13
|
+
* reference to the alias is pointed at the column it answers with.
|
|
14
14
|
*
|
|
15
15
|
* Answers with whether the statement can run. A statement carrying no `UNNEST`
|
|
16
16
|
* runs untouched, and one carrying an `UNNEST` this cannot turn into
|
|
@@ -6,10 +6,10 @@ import { simAthenaUnnestTargets } from "./sim-athena-unnest-targets.js";
|
|
|
6
6
|
/**
|
|
7
7
|
* Turn an `UNNEST` into the `json_each` SQLite flattens JSON with.
|
|
8
8
|
*
|
|
9
|
-
* An array or a map column is held as its JSON text,
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* answers with.
|
|
9
|
+
* An array or a map column is held as its JSON text, as is what a function like
|
|
10
|
+
* `split` answers, and `json_each` reads that as one row per element with a
|
|
11
|
+
* `key` and a `value`. The `FROM` entry becomes a call to it and every
|
|
12
|
+
* reference to the alias is pointed at the column it answers with.
|
|
13
13
|
*
|
|
14
14
|
* Answers with whether the statement can run. A statement carrying no `UNNEST`
|
|
15
15
|
* runs untouched, and one carrying an `UNNEST` this cannot turn into
|
|
@@ -3,17 +3,18 @@ import { type SimAthenaAstNode } from "./sim-athena-ast-nodes.js";
|
|
|
3
3
|
/** The two things Athena flattens with `UNNEST`. */
|
|
4
4
|
export type SimAthenaUnnestKind = "array" | "map";
|
|
5
5
|
/**
|
|
6
|
-
* What the statement is flattening
|
|
6
|
+
* What the statement is flattening.
|
|
7
7
|
*
|
|
8
|
-
* The catalog is the only thing that says
|
|
9
|
-
* map or a scalar, and `json_each` answers
|
|
10
|
-
* two. A column the schema calls anything
|
|
11
|
-
* the query falls back rather than reading
|
|
12
|
-
* was.
|
|
8
|
+
* A column is read off the Glue schema. The catalog is the only thing that says
|
|
9
|
+
* whether a column holds an array, a map or a scalar, and `json_each` answers
|
|
10
|
+
* with different columns for the first two. A column the schema calls anything
|
|
11
|
+
* else answers with nothing here, and the query falls back rather than reading
|
|
12
|
+
* a value as a collection it never was.
|
|
13
13
|
*
|
|
14
|
-
* An expression
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* An expression is read off the function it calls. `UNNEST(split(x, ','))` is
|
|
15
|
+
* how a statement flattens a delimited string, and nothing but the call says
|
|
16
|
+
* what it comes to. A call to anything else answers with nothing, since the
|
|
17
|
+
* flattening would otherwise run over whatever SQLite made of a scalar.
|
|
17
18
|
*/
|
|
18
19
|
export declare function simAthenaUnnestKind(source: SimAthenaAstNode, ast: unknown, tables: readonly SimAthenaCatalogTable[]): SimAthenaUnnestKind | undefined;
|
|
19
20
|
/** Every catalog table the statement reads, by the name it reaches each one by. */
|
|
@@ -1,20 +1,29 @@
|
|
|
1
|
-
import { isColumnRef, isFromItem, simAthenaAstNodes, } from "./sim-athena-ast-nodes.js";
|
|
1
|
+
import { isColumnRef, isFromItem, simAthenaAstNodes, simAthenaCalledName, } from "./sim-athena-ast-nodes.js";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* The engine's own functions that answer an array.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
* An expression has no catalog entry to read, so the call itself is what says
|
|
6
|
+
* the value is a collection. Each of these answers with the JSON text an array
|
|
7
|
+
* column is held as, which is what `json_each` reads.
|
|
8
|
+
*/
|
|
9
|
+
const arrayFunctions = new Set(["split", "slice"]);
|
|
10
|
+
/**
|
|
11
|
+
* What the statement is flattening.
|
|
12
|
+
*
|
|
13
|
+
* A column is read off the Glue schema. The catalog is the only thing that says
|
|
14
|
+
* whether a column holds an array, a map or a scalar, and `json_each` answers
|
|
15
|
+
* with different columns for the first two. A column the schema calls anything
|
|
16
|
+
* else answers with nothing here, and the query falls back rather than reading
|
|
17
|
+
* a value as a collection it never was.
|
|
10
18
|
*
|
|
11
|
-
* An expression
|
|
12
|
-
*
|
|
13
|
-
*
|
|
19
|
+
* An expression is read off the function it calls. `UNNEST(split(x, ','))` is
|
|
20
|
+
* how a statement flattens a delimited string, and nothing but the call says
|
|
21
|
+
* what it comes to. A call to anything else answers with nothing, since the
|
|
22
|
+
* flattening would otherwise run over whatever SQLite made of a scalar.
|
|
14
23
|
*/
|
|
15
24
|
export function simAthenaUnnestKind(source, ast, tables) {
|
|
16
25
|
if (!isColumnRef(source)) {
|
|
17
|
-
return undefined;
|
|
26
|
+
return answersArray(source) ? "array" : undefined;
|
|
18
27
|
}
|
|
19
28
|
const declared = declaredType(source, ast, tables);
|
|
20
29
|
if (declared === undefined) {
|
|
@@ -26,6 +35,11 @@ export function simAthenaUnnestKind(source, ast, tables) {
|
|
|
26
35
|
}
|
|
27
36
|
return type.startsWith("map") ? "map" : undefined;
|
|
28
37
|
}
|
|
38
|
+
/** Whether this expression is a call to a function answering an array. */
|
|
39
|
+
function answersArray(source) {
|
|
40
|
+
const name = source["type"] === "function" ? simAthenaCalledName(source) : undefined;
|
|
41
|
+
return name !== undefined && arrayFunctions.has(name.toLowerCase());
|
|
42
|
+
}
|
|
29
43
|
/** Every catalog table the statement reads, by the name it reaches each one by. */
|
|
30
44
|
export function simAthenaQueryTables(ast, tables) {
|
|
31
45
|
const byName = new Map();
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { aCatalogTable, anEngineSimulation, aSeededJson, } from "./sim-athena-engine.fixture.js";
|
|
2
|
+
/**
|
|
3
|
+
* The events a flattening query reads.
|
|
4
|
+
*
|
|
5
|
+
* Each holds a collection of every shape an `UNNEST` reaches. An array and a
|
|
6
|
+
* map that are empty, a delimited string that is empty, and a row carrying no
|
|
7
|
+
* delimited string at all, which is what a flattening answering no rows runs
|
|
8
|
+
* over.
|
|
9
|
+
*/
|
|
10
|
+
const events = [
|
|
11
|
+
{
|
|
12
|
+
id: 1,
|
|
13
|
+
tags: ["red", "blue"],
|
|
14
|
+
attrs: { size: "large" },
|
|
15
|
+
name: "one",
|
|
16
|
+
packed: "red;blue",
|
|
17
|
+
},
|
|
18
|
+
{ id: 2, tags: [], attrs: {}, name: "two", packed: "" },
|
|
19
|
+
{
|
|
20
|
+
id: 3,
|
|
21
|
+
tags: ["green"],
|
|
22
|
+
attrs: { size: "small", colour: "green" },
|
|
23
|
+
name: "three",
|
|
24
|
+
},
|
|
25
|
+
];
|
|
26
|
+
/** A simulation holding the events, with the engine on. */
|
|
27
|
+
export async function anEventSimulation() {
|
|
28
|
+
const simulation = await anEngineSimulation();
|
|
29
|
+
aCatalogTable(simulation.simAws, {
|
|
30
|
+
name: "events",
|
|
31
|
+
columns: [
|
|
32
|
+
{ Name: "id", Type: "int" },
|
|
33
|
+
{ Name: "tags", Type: "array<string>" },
|
|
34
|
+
{ Name: "attrs", Type: "map<string,string>" },
|
|
35
|
+
{ Name: "name", Type: "string" },
|
|
36
|
+
{ Name: "packed", Type: "string" },
|
|
37
|
+
],
|
|
38
|
+
});
|
|
39
|
+
await aSeededJson(simulation.simAws, "events/part-0.json", events);
|
|
40
|
+
await simulation.simAws.athena().engine().enable();
|
|
41
|
+
simulation.simAws
|
|
42
|
+
.athena()
|
|
43
|
+
.results()
|
|
44
|
+
.byDefault({ columns: ["fallback"], rows: [["declared"]] });
|
|
45
|
+
return simulation;
|
|
46
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SimWafUnsimulatedResource } from "./sim-waf-unsimulated-resource.js";
|
|
1
2
|
/**
|
|
2
3
|
* The resources of one simulated AWS instance a web ACL can be put in front
|
|
3
4
|
* of.
|
|
@@ -19,6 +20,9 @@ export class SimAwsWafProtectedResources {
|
|
|
19
20
|
* Whether the resource an ARN names is one this scope holds.
|
|
20
21
|
*/
|
|
21
22
|
has(resource) {
|
|
23
|
+
if (resource instanceof SimWafUnsimulatedResource) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
22
26
|
if (resource.resourceType === "COGNITO_USER_POOL") {
|
|
23
27
|
return this.hasUserPool(resource);
|
|
24
28
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { SimWafDecision } from "../evaluate/sim-waf-decision.js";
|
|
2
|
+
import type { SimWafUnsimulatedPart } from "../resource/sim-waf-unsimulated-part.js";
|
|
2
3
|
import type { SimWafWebAcl } from "../web-acl/sim-waf-web-acl.js";
|
|
3
4
|
import type { SimWafProtectedResource, SimWafProtectedResourceType } from "./sim-waf-protected-resource.js";
|
|
4
5
|
import type { SimWafProtectedRequest, SimWafProtection } from "./sim-waf-protection.js";
|
|
@@ -32,6 +33,11 @@ export declare class SimWafAssociations implements SimWafProtection {
|
|
|
32
33
|
* is what `DeleteWebACL` asks for when it refuses a web ACL still in use.
|
|
33
34
|
*/
|
|
34
35
|
resourceArnsFor(webAcl: SimWafWebAcl, resourceType?: SimWafProtectedResourceType): readonly string[];
|
|
36
|
+
/**
|
|
37
|
+
* The associations of one web ACL that nothing is evaluated through, one
|
|
38
|
+
* part per resource ARN.
|
|
39
|
+
*/
|
|
40
|
+
unsimulatedFor(webAcl: SimWafWebAcl): readonly SimWafUnsimulatedPart[];
|
|
35
41
|
/**
|
|
36
42
|
* Whether a web ACL is in front of one resource.
|
|
37
43
|
*/
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { simWafInspectedRequest } from "../evaluate/sim-waf-inspected-request.js";
|
|
2
|
+
import { SimWafUnsimulatedResource } from "./sim-waf-unsimulated-resource.js";
|
|
2
3
|
/**
|
|
3
4
|
* The web ACLs one Account and Region has in front of things.
|
|
4
5
|
*
|
|
@@ -19,6 +20,9 @@ export class SimWafAssociations {
|
|
|
19
20
|
this.#associations.set(resource.arn, {
|
|
20
21
|
webAcl,
|
|
21
22
|
resourceType: resource.resourceType,
|
|
23
|
+
unsimulatedReason: resource instanceof SimWafUnsimulatedResource
|
|
24
|
+
? resource.reason
|
|
25
|
+
: undefined,
|
|
22
26
|
});
|
|
23
27
|
}
|
|
24
28
|
/**
|
|
@@ -44,6 +48,19 @@ export class SimWafAssociations {
|
|
|
44
48
|
.map(([resourceArn]) => resourceArn)
|
|
45
49
|
.toArray();
|
|
46
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* The associations of one web ACL that nothing is evaluated through, one
|
|
53
|
+
* part per resource ARN.
|
|
54
|
+
*/
|
|
55
|
+
unsimulatedFor(webAcl) {
|
|
56
|
+
return this.#associations
|
|
57
|
+
.entries()
|
|
58
|
+
.filter(([, association]) => association.webAcl === webAcl)
|
|
59
|
+
.flatMap(([resourceArn, { unsimulatedReason }]) => unsimulatedReason === undefined
|
|
60
|
+
? []
|
|
61
|
+
: [{ part: `Association.${resourceArn}`, reason: unsimulatedReason }])
|
|
62
|
+
.toArray();
|
|
63
|
+
}
|
|
47
64
|
/**
|
|
48
65
|
* Whether a web ACL is in front of one resource.
|
|
49
66
|
*/
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { SimWafRestApiStage } from "./sim-waf-rest-api-stage.js";
|
|
2
|
+
import { SimWafUnsimulatedResource } from "./sim-waf-unsimulated-resource.js";
|
|
2
3
|
import { SimWafUserPool } from "./sim-waf-user-pool.js";
|
|
3
4
|
/**
|
|
4
5
|
* A resource a `REGIONAL` web ACL can be put in front of.
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
7
|
+
* Requests reach a web ACL through two types here. The rest are held as
|
|
8
|
+
* `SimWafUnsimulatedResource`, associated and listed, with nothing evaluated
|
|
9
|
+
* in front of them. A type that starts serving requests gets a class of its
|
|
10
|
+
* own in this union, and everything that holds an association goes on
|
|
8
11
|
* addressing a resource by its ARN.
|
|
9
12
|
*/
|
|
10
|
-
export type SimWafProtectedResource = SimWafRestApiStage | SimWafUserPool;
|
|
13
|
+
export type SimWafProtectedResource = SimWafRestApiStage | SimWafUserPool | SimWafUnsimulatedResource;
|
|
11
14
|
/**
|
|
12
15
|
* The type ListResourcesForWebACL lists one simulated resource under.
|
|
13
16
|
*/
|
|
@@ -21,17 +24,19 @@ export declare const simWafApiGatewayResourceType = "API_GATEWAY";
|
|
|
21
24
|
*/
|
|
22
25
|
export declare const simWafUserPoolResourceType = "COGNITO_USER_POOL";
|
|
23
26
|
/**
|
|
24
|
-
* The resource types
|
|
27
|
+
* The resource types ListResourcesForWebACL lists, which are all the types
|
|
28
|
+
* an association can hold.
|
|
25
29
|
*/
|
|
26
30
|
export declare const simWafProtectedResourceTypes: readonly SimWafProtectedResourceType[];
|
|
27
31
|
/**
|
|
28
32
|
* Read the resource an association names, refusing anything a web ACL cannot
|
|
29
|
-
* be put in front of
|
|
33
|
+
* be put in front of.
|
|
30
34
|
*
|
|
31
35
|
* The three refusals mean different things. An HTTP API stage is refused
|
|
32
36
|
* because AWS WAF protects no HTTP API, so an association accepted here would
|
|
33
|
-
* let a test cover protection AWS never applies.
|
|
34
|
-
*
|
|
35
|
-
*
|
|
37
|
+
* let a test cover protection AWS never applies. An Amplify app takes a
|
|
38
|
+
* `CLOUDFRONT` web ACL from `us-east-1` for an app in any Region, and a WAFv2
|
|
39
|
+
* here reaches web ACLs in its own Region only. Anything else is not a
|
|
40
|
+
* resource ARN.
|
|
36
41
|
*/
|
|
37
42
|
export declare function simWafProtectedResource(arn: string): SimWafProtectedResource;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SimWafInvalidParameterException, SimWafUnsimulatedInputException, } from "../error/sim-wafv2.error.js";
|
|
2
2
|
import { SimWafRestApiStage } from "./sim-waf-rest-api-stage.js";
|
|
3
|
+
import { SimWafUnsimulatedResource, simWafUnsimulatedResourceTypes, } from "./sim-waf-unsimulated-resource.js";
|
|
3
4
|
import { SimWafUserPool } from "./sim-waf-user-pool.js";
|
|
4
5
|
/**
|
|
5
6
|
* The type ListResourcesForWebACL lists a simulated REST API stage under.
|
|
@@ -10,32 +11,28 @@ export const simWafApiGatewayResourceType = "API_GATEWAY";
|
|
|
10
11
|
*/
|
|
11
12
|
export const simWafUserPoolResourceType = "COGNITO_USER_POOL";
|
|
12
13
|
/**
|
|
13
|
-
* The resource types
|
|
14
|
+
* The resource types ListResourcesForWebACL lists, which are all the types
|
|
15
|
+
* an association can hold.
|
|
14
16
|
*/
|
|
15
|
-
export const simWafProtectedResourceTypes = [
|
|
17
|
+
export const simWafProtectedResourceTypes = [
|
|
18
|
+
simWafApiGatewayResourceType,
|
|
19
|
+
simWafUserPoolResourceType,
|
|
20
|
+
...simWafUnsimulatedResourceTypes,
|
|
21
|
+
];
|
|
16
22
|
const restApiStagePattern = /^arn:aws:apigateway:(?<regionName>[^:]+)::\/restapis\/(?<restApiId>[^/]+)\/stages\/(?<stageName>[^/]+)$/u;
|
|
17
23
|
const httpApiStagePattern = /^arn:aws:apigateway:[^:]+::\/apis\/[^/]+\/stages\/[^/]+$/u;
|
|
18
24
|
const userPoolPattern = /^arn:aws:cognito-idp:(?<regionName>[^:]+):(?<accountId>[^:]+):userpool\/(?<userPoolId>[^/]+)$/u;
|
|
19
|
-
|
|
20
|
-
* The resource types real WAF protects that this simulation does not, by the
|
|
21
|
-
* service in their ARN.
|
|
22
|
-
*/
|
|
23
|
-
const unsimulatedResources = new Map([
|
|
24
|
-
["elasticloadbalancing", "an Application Load Balancer"],
|
|
25
|
-
["appsync", "an AppSync GraphQL API"],
|
|
26
|
-
["apprunner", "an App Runner service"],
|
|
27
|
-
["amplify", "an Amplify app"],
|
|
28
|
-
["ec2", "a Verified Access instance"],
|
|
29
|
-
]);
|
|
25
|
+
const amplifyAppPattern = /^arn:aws:amplify:[^:]+:[^:]+:apps\/[^/]+$/u;
|
|
30
26
|
/**
|
|
31
27
|
* Read the resource an association names, refusing anything a web ACL cannot
|
|
32
|
-
* be put in front of
|
|
28
|
+
* be put in front of.
|
|
33
29
|
*
|
|
34
30
|
* The three refusals mean different things. An HTTP API stage is refused
|
|
35
31
|
* because AWS WAF protects no HTTP API, so an association accepted here would
|
|
36
|
-
* let a test cover protection AWS never applies.
|
|
37
|
-
*
|
|
38
|
-
*
|
|
32
|
+
* let a test cover protection AWS never applies. An Amplify app takes a
|
|
33
|
+
* `CLOUDFRONT` web ACL from `us-east-1` for an app in any Region, and a WAFv2
|
|
34
|
+
* here reaches web ACLs in its own Region only. Anything else is not a
|
|
35
|
+
* resource ARN.
|
|
39
36
|
*/
|
|
40
37
|
export function simWafProtectedResource(arn) {
|
|
41
38
|
const stage = restApiStage(arn);
|
|
@@ -46,6 +43,10 @@ export function simWafProtectedResource(arn) {
|
|
|
46
43
|
if (userPool !== undefined) {
|
|
47
44
|
return userPool;
|
|
48
45
|
}
|
|
46
|
+
const unsimulated = SimWafUnsimulatedResource.read(arn);
|
|
47
|
+
if (unsimulated !== undefined) {
|
|
48
|
+
return unsimulated;
|
|
49
|
+
}
|
|
49
50
|
if (httpApiStagePattern.test(arn)) {
|
|
50
51
|
throw new SimWafInvalidParameterException(`AWS WAF does not protect an API Gateway HTTP API. The resource types ` +
|
|
51
52
|
`it protects cover a REST API stage and not an HTTP API stage, so ` +
|
|
@@ -87,13 +88,12 @@ function simWafUserPool(arn) {
|
|
|
87
88
|
});
|
|
88
89
|
}
|
|
89
90
|
/**
|
|
90
|
-
* Refuse an
|
|
91
|
+
* Refuse an Amplify app, whose web ACL is out of this WAFv2's reach.
|
|
91
92
|
*/
|
|
92
93
|
function refuseUnsimulatedResource(arn) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
`
|
|
97
|
-
`nothing.`);
|
|
94
|
+
if (amplifyAppPattern.test(arn)) {
|
|
95
|
+
throw new SimWafUnsimulatedInputException(`AWS WAF protects an Amplify app with a CLOUDFRONT web ACL held in ` +
|
|
96
|
+
`us-east-1, and a simulated WAFv2 associates web ACLs of its own ` +
|
|
97
|
+
`Region only, so ${arn} is refused.`);
|
|
98
98
|
}
|
|
99
99
|
}
|
|
@@ -9,20 +9,25 @@ import type { SimWafProtectedResource } from "./sim-waf-protected-resource.js";
|
|
|
9
9
|
export interface SimWafProtectedResources {
|
|
10
10
|
/**
|
|
11
11
|
* Whether this simulation holds the resource an ARN names.
|
|
12
|
+
*
|
|
13
|
+
* A `SimWafUnsimulatedResource` is held by no simulated service, so there is
|
|
14
|
+
* nothing to look for, and it is taken as named.
|
|
12
15
|
*/
|
|
13
16
|
has(resource: SimWafProtectedResource): boolean;
|
|
14
17
|
}
|
|
15
18
|
/**
|
|
16
19
|
* The resources available to a WAFv2 with nothing around it to ask.
|
|
17
20
|
*
|
|
18
|
-
* Every ARN resolves to nothing, so a standalone simulated
|
|
19
|
-
* web ACL with
|
|
20
|
-
* against a resource no request will ever reach protects
|
|
21
|
-
* so is better than reporting a web ACL in front of
|
|
21
|
+
* Every simulated resource ARN resolves to nothing, so a standalone simulated
|
|
22
|
+
* WAFv2 associates a web ACL with no stage or pool. That is the safe answer:
|
|
23
|
+
* an association held against a resource no request will ever reach protects
|
|
24
|
+
* nothing, and saying so is better than reporting a web ACL in front of
|
|
25
|
+
* something imaginary. A `SimWafUnsimulatedResource` is taken as named here
|
|
26
|
+
* as everywhere else.
|
|
22
27
|
*/
|
|
23
28
|
export declare class SimWafNoProtectedResources implements SimWafProtectedResources {
|
|
24
29
|
/**
|
|
25
|
-
*
|
|
30
|
+
* Whether the resource is one no simulated service holds.
|
|
26
31
|
*/
|
|
27
|
-
has(): boolean;
|
|
32
|
+
has(resource: SimWafProtectedResource): boolean;
|
|
28
33
|
}
|
|
@@ -1,16 +1,19 @@
|
|
|
1
|
+
import { SimWafUnsimulatedResource } from "./sim-waf-unsimulated-resource.js";
|
|
1
2
|
/**
|
|
2
3
|
* The resources available to a WAFv2 with nothing around it to ask.
|
|
3
4
|
*
|
|
4
|
-
* Every ARN resolves to nothing, so a standalone simulated
|
|
5
|
-
* web ACL with
|
|
6
|
-
* against a resource no request will ever reach protects
|
|
7
|
-
* so is better than reporting a web ACL in front of
|
|
5
|
+
* Every simulated resource ARN resolves to nothing, so a standalone simulated
|
|
6
|
+
* WAFv2 associates a web ACL with no stage or pool. That is the safe answer:
|
|
7
|
+
* an association held against a resource no request will ever reach protects
|
|
8
|
+
* nothing, and saying so is better than reporting a web ACL in front of
|
|
9
|
+
* something imaginary. A `SimWafUnsimulatedResource` is taken as named here
|
|
10
|
+
* as everywhere else.
|
|
8
11
|
*/
|
|
9
12
|
export class SimWafNoProtectedResources {
|
|
10
13
|
/**
|
|
11
|
-
*
|
|
14
|
+
* Whether the resource is one no simulated service holds.
|
|
12
15
|
*/
|
|
13
|
-
has() {
|
|
14
|
-
return
|
|
16
|
+
has(resource) {
|
|
17
|
+
return resource instanceof SimWafUnsimulatedResource;
|
|
15
18
|
}
|
|
16
19
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The resource types AWS WAF protects that no simulated request passes
|
|
3
|
+
* through, as ListResourcesForWebACL lists them.
|
|
4
|
+
*/
|
|
5
|
+
export type SimWafUnsimulatedResourceType = "APPLICATION_LOAD_BALANCER" | "APPSYNC" | "APP_RUNNER_SERVICE" | "VERIFIED_ACCESS_INSTANCE";
|
|
6
|
+
/**
|
|
7
|
+
* The types listed for a resource AWS WAF protects and Yulin does not.
|
|
8
|
+
*/
|
|
9
|
+
export declare const simWafUnsimulatedResourceTypes: readonly SimWafUnsimulatedResourceType[];
|
|
10
|
+
/**
|
|
11
|
+
* A resource AWS WAF protects and no simulated request passes through.
|
|
12
|
+
*
|
|
13
|
+
* An association with one is held, and GetWebACLForResource and
|
|
14
|
+
* ListResourcesForWebACL report it. Nothing is evaluated in front of it,
|
|
15
|
+
* because nothing here serves a request through it. Whether the resource
|
|
16
|
+
* exists is not checked, since no simulated service holds it to ask.
|
|
17
|
+
*/
|
|
18
|
+
export declare class SimWafUnsimulatedResource {
|
|
19
|
+
readonly resourceType: SimWafUnsimulatedResourceType;
|
|
20
|
+
readonly arn: string;
|
|
21
|
+
readonly regionName: string;
|
|
22
|
+
readonly accountId: string;
|
|
23
|
+
/** Why the web ACL in front of this resource evaluates nothing. */
|
|
24
|
+
readonly reason: string;
|
|
25
|
+
private constructor();
|
|
26
|
+
/**
|
|
27
|
+
* The unsimulated resource an ARN names, or nothing when it names none.
|
|
28
|
+
*
|
|
29
|
+
* Every pattern places the Region and the Account where any ARN does, so a
|
|
30
|
+
* match is read for them by position.
|
|
31
|
+
*/
|
|
32
|
+
static read(arn: string): SimWafUnsimulatedResource | undefined;
|
|
33
|
+
}
|