Skip to content

Commit f9530d8

Browse files
committed
Merge branch 'backport/7.15/pr-110472' of github.com:semd/kibana into backport/7.15/pr-110472
2 parents 9853fa2 + e0b9d7e commit f9530d8

File tree

60 files changed

+1683
-1112
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+1683
-1112
lines changed

.ci/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# NOTE: This Dockerfile is ONLY used to run certain tasks in CI. It is not used to run Kibana or as a distributable.
22
# If you're looking for the Kibana Docker image distributable, please see: src/dev/build/tasks/os_packages/docker_generator/templates/dockerfile.template.ts
33

4-
ARG NODE_VERSION=14.17.5
4+
ARG NODE_VERSION=14.17.6
55

66
FROM node:${NODE_VERSION} AS base
77

.node-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
14.17.5
1+
14.17.6

.nvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
14.17.5
1+
14.17.6

WORKSPACE.bazel

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ check_rules_nodejs_version(minimum_version_string = "3.8.0")
2727
# we can update that rule.
2828
node_repositories(
2929
node_repositories = {
30-
"14.17.5-darwin_amd64": ("node-v14.17.5-darwin-x64.tar.gz", "node-v14.17.5-darwin-x64", "2e40ab625b45b9bdfcb963ddd4d65d87ddf1dd37a86b6f8b075cf3d77fe9dc09"),
31-
"14.17.5-linux_arm64": ("node-v14.17.5-linux-arm64.tar.xz", "node-v14.17.5-linux-arm64", "3a2e674b6db50dfde767c427e8f077235bbf6f9236e1b12a4cc3496b12f94bae"),
32-
"14.17.5-linux_s390x": ("node-v14.17.5-linux-s390x.tar.xz", "node-v14.17.5-linux-s390x", "7d40eee3d54241403db12fb3bc420cd776e2b02e89100c45cf5e74a73942e7f6"),
33-
"14.17.5-linux_amd64": ("node-v14.17.5-linux-x64.tar.xz", "node-v14.17.5-linux-x64", "2d759de07a50cd7f75bd73d67e97b0d0e095ee3c413efac7d1b3d1e84ed76fff"),
34-
"14.17.5-windows_amd64": ("node-v14.17.5-win-x64.zip", "node-v14.17.5-win-x64", "a99b7ee08e846e5d1f4e70c4396265542819d79ed9cebcc27760b89571f03cbf"),
30+
"14.17.6-darwin_amd64": ("node-v14.17.6-darwin-x64.tar.gz", "node-v14.17.6-darwin-x64", "e3e4c02240d74fb1dc8a514daa62e5de04f7eaee0bcbca06a366ece73a52ad88"),
31+
"14.17.6-linux_arm64": ("node-v14.17.6-linux-arm64.tar.xz", "node-v14.17.6-linux-arm64", "9c4f3a651e03cd9b5bddd33a80e8be6a6eb15e518513e410bb0852a658699156"),
32+
"14.17.6-linux_s390x": ("node-v14.17.6-linux-s390x.tar.xz", "node-v14.17.6-linux-s390x", "3677f35b97608056013b5368f86eecdb044bdccc1b3976c1d4448736c37b6a0c"),
33+
"14.17.6-linux_amd64": ("node-v14.17.6-linux-x64.tar.xz", "node-v14.17.6-linux-x64", "3bbe4faf356738d88b45be222bf5e858330541ff16bd0d4cfad36540c331461b"),
34+
"14.17.6-windows_amd64": ("node-v14.17.6-win-x64.zip", "node-v14.17.6-win-x64", "b83e9ce542fda7fc519cec6eb24a2575a84862ea4227dedc171a8e0b5b614ac0"),
3535
},
36-
node_version = "14.17.5",
36+
node_version = "14.17.6",
3737
node_urls = [
3838
"https://nodejs.org/dist/v{version}/{filename}",
3939
],

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@
8686
"**/underscore": "^1.13.1"
8787
},
8888
"engines": {
89-
"node": "14.17.5",
89+
"node": "14.17.6",
9090
"yarn": "^1.21.1"
9191
},
9292
"dependencies": {
@@ -656,6 +656,7 @@
656656
"@types/yauzl": "^2.9.1",
657657
"@types/zen-observable": "^0.8.0",
658658
"@typescript-eslint/eslint-plugin": "^4.14.1",
659+
"@typescript-eslint/typescript-estree": "^4.14.1",
659660
"@typescript-eslint/parser": "^4.14.1",
660661
"@yarnpkg/lockfile": "^1.1.0",
661662
"abab": "^2.0.4",
@@ -725,6 +726,7 @@
725726
"eslint-plugin-react": "^7.20.3",
726727
"eslint-plugin-react-hooks": "^4.2.0",
727728
"eslint-plugin-react-perf": "^3.2.3",
729+
"eslint-traverse": "^1.0.0",
728730
"expose-loader": "^0.7.5",
729731
"faker": "^5.1.0",
730732
"fancy-log": "^1.3.2",

packages/elastic-eslint-config-kibana/.eslintrc.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,5 +90,7 @@ module.exports = {
9090
},
9191
],
9292
],
93+
94+
'@kbn/eslint/no_async_promise_body': 'error',
9395
},
9496
};

packages/kbn-eslint-plugin-eslint/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ module.exports = {
1212
'disallow-license-headers': require('./rules/disallow_license_headers'),
1313
'no-restricted-paths': require('./rules/no_restricted_paths'),
1414
module_migration: require('./rules/module_migration'),
15+
no_async_promise_body: require('./rules/no_async_promise_body'),
1516
},
1617
};
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
const { parseExpression } = require('@babel/parser');
10+
const { default: generate } = require('@babel/generator');
11+
const tsEstree = require('@typescript-eslint/typescript-estree');
12+
const traverse = require('eslint-traverse');
13+
const esTypes = tsEstree.AST_NODE_TYPES;
14+
const babelTypes = require('@babel/types');
15+
16+
/** @typedef {import("eslint").Rule.RuleModule} Rule */
17+
/** @typedef {import("@typescript-eslint/parser").ParserServices} ParserServices */
18+
/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.Expression} Expression */
19+
/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.ArrowFunctionExpression} ArrowFunctionExpression */
20+
/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.FunctionExpression} FunctionExpression */
21+
/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.TryStatement} TryStatement */
22+
/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.NewExpression} NewExpression */
23+
/** @typedef {import("typescript").ExportDeclaration} ExportDeclaration */
24+
/** @typedef {import("eslint").Rule.RuleFixer} Fixer */
25+
26+
const ERROR_MSG =
27+
'Passing an async function to the Promise constructor leads to a hidden promise being created and prevents handling rejections';
28+
29+
/**
30+
* @param {Expression} node
31+
*/
32+
const isPromise = (node) => node.type === esTypes.Identifier && node.name === 'Promise';
33+
34+
/**
35+
* @param {Expression} node
36+
* @returns {node is ArrowFunctionExpression | FunctionExpression}
37+
*/
38+
const isFunc = (node) =>
39+
node.type === esTypes.ArrowFunctionExpression || node.type === esTypes.FunctionExpression;
40+
41+
/**
42+
* @param {any} context
43+
* @param {ArrowFunctionExpression | FunctionExpression} node
44+
*/
45+
const isFuncBodySafe = (context, node) => {
46+
// if the body isn't wrapped in a blockStatement it can't have a try/catch at the root
47+
if (node.body.type !== esTypes.BlockStatement) {
48+
return false;
49+
}
50+
51+
// when the entire body is wrapped in a try/catch it is the only node
52+
if (node.body.body.length !== 1) {
53+
return false;
54+
}
55+
56+
const tryNode = node.body.body[0];
57+
// ensure we have a try node with a handler
58+
if (tryNode.type !== esTypes.TryStatement || !tryNode.handler) {
59+
return false;
60+
}
61+
62+
// ensure the handler doesn't throw
63+
let hasThrow = false;
64+
traverse(context, tryNode.handler, (path) => {
65+
if (path.node.type === esTypes.ThrowStatement) {
66+
hasThrow = true;
67+
return traverse.STOP;
68+
}
69+
});
70+
return !hasThrow;
71+
};
72+
73+
/**
74+
* @param {string} code
75+
*/
76+
const wrapFunctionInTryCatch = (code) => {
77+
// parse the code with babel so we can mutate the AST
78+
const ast = parseExpression(code, {
79+
plugins: ['typescript', 'jsx'],
80+
});
81+
82+
// validate that the code reperesents an arrow or function expression
83+
if (!babelTypes.isArrowFunctionExpression(ast) && !babelTypes.isFunctionExpression(ast)) {
84+
throw new Error('expected function to be an arrow or function expression');
85+
}
86+
87+
// ensure that the function receives the second argument, and capture its name if already defined
88+
let rejectName = 'reject';
89+
if (ast.params.length === 0) {
90+
ast.params.push(babelTypes.identifier('resolve'), babelTypes.identifier(rejectName));
91+
} else if (ast.params.length === 1) {
92+
ast.params.push(babelTypes.identifier(rejectName));
93+
} else if (ast.params.length === 2) {
94+
if (babelTypes.isIdentifier(ast.params[1])) {
95+
rejectName = ast.params[1].name;
96+
} else {
97+
throw new Error('expected second param of promise definition function to be an identifier');
98+
}
99+
}
100+
101+
// ensure that the body of the function is a blockStatement
102+
let block = ast.body;
103+
if (!babelTypes.isBlockStatement(block)) {
104+
block = babelTypes.blockStatement([babelTypes.returnStatement(block)]);
105+
}
106+
107+
// redefine the body of the function as a new blockStatement containing a tryStatement
108+
// which catches errors and forwards them to reject() when caught
109+
ast.body = babelTypes.blockStatement([
110+
// try {
111+
babelTypes.tryStatement(
112+
block,
113+
// catch (error) {
114+
babelTypes.catchClause(
115+
babelTypes.identifier('error'),
116+
babelTypes.blockStatement([
117+
// reject(error)
118+
babelTypes.expressionStatement(
119+
babelTypes.callExpression(babelTypes.identifier(rejectName), [
120+
babelTypes.identifier('error'),
121+
])
122+
),
123+
])
124+
)
125+
),
126+
]);
127+
128+
return generate(ast).code;
129+
};
130+
131+
/** @type {Rule} */
132+
module.exports = {
133+
meta: {
134+
fixable: 'code',
135+
schema: [],
136+
},
137+
create: (context) => ({
138+
NewExpression(_) {
139+
const node = /** @type {NewExpression} */ (_);
140+
141+
// ensure we are newing up a promise with a single argument
142+
if (!isPromise(node.callee) || node.arguments.length !== 1) {
143+
return;
144+
}
145+
146+
const func = node.arguments[0];
147+
// ensure the argument is an arrow or function expression and is async
148+
if (!isFunc(func) || !func.async) {
149+
return;
150+
}
151+
152+
// body must be a blockStatement, try/catch can't exist outside of a block
153+
if (!isFuncBodySafe(context, func)) {
154+
context.report({
155+
message: ERROR_MSG,
156+
loc: func.loc,
157+
fix(fixer) {
158+
const source = context.getSourceCode();
159+
return fixer.replaceText(func, wrapFunctionInTryCatch(source.getText(func)));
160+
},
161+
});
162+
}
163+
},
164+
}),
165+
};

0 commit comments

Comments
 (0)