mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
Harden console functions (#171367)
## Summary This PR overrides console functions only in production, in order to sanitize input parameters for any potential calls made to the global console from Kibana's dependencies. This initial implementation overrides the `debug`, `error`, `info`, `log`, `trace`, and `warn` functions, and only sanitizes string inputs. Future updates may expand this to handle other types, or strings nested in objects. The unmodified console methods are now exposed internally in Kibana as `unsafeConsole`. Where needed for formatting (log appenders, core logger), calls to the global console have been replaced by `unsafeConsole`. This PR also adds a new es linting rule to disallow calls to `unsafeConsole` unless `eslint-disable-next-line @kbn/eslint/no_unsafe_console` is used. ### Testing Not sure how we could test this. The overrides are only enabled when running in a true production environment (e.g. docker) by checking `process.env.NODE_ENV`. I was able to manually test by adding additional console output denoting when the console functions were being overriden or not. Closes https://github.com/elastic/kibana-team/issues/664 Closes #176340 --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
c5819dc09e
commit
2627f48d95
34 changed files with 379 additions and 47 deletions
|
@ -103,4 +103,8 @@ module.exports = {
|
|||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
## no_unsafe_console
|
||||
|
||||
Disables the usage of kbn-security-hardening/console/unsafeConsole.
|
|
@ -17,5 +17,6 @@ module.exports = {
|
|||
no_trailing_import_slash: require('./rules/no_trailing_import_slash'),
|
||||
no_constructor_args_in_property_initializers: require('./rules/no_constructor_args_in_property_initializers'),
|
||||
no_this_in_property_initializers: require('./rules/no_this_in_property_initializers'),
|
||||
no_unsafe_console: require('./rules/no_unsafe_console'),
|
||||
},
|
||||
};
|
||||
|
|
71
packages/kbn-eslint-plugin-eslint/rules/no_unsafe_console.js
Normal file
71
packages/kbn-eslint-plugin-eslint/rules/no_unsafe_console.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
const tsEstree = require('@typescript-eslint/typescript-estree');
|
||||
const esTypes = tsEstree.AST_NODE_TYPES;
|
||||
|
||||
/** @typedef {import("eslint").Rule.RuleModule} Rule */
|
||||
/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.Node} Node */
|
||||
/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.CallExpression} CallExpression */
|
||||
/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.CallExpression} VariableDeclarator */
|
||||
|
||||
const ERROR_MSG = 'Unexpected unsafeConsole statement.';
|
||||
|
||||
/**
|
||||
* @param {CallExpression} node
|
||||
*/
|
||||
const isUnsafeConsoleCall = (node) => {
|
||||
return (
|
||||
node.callee.type === esTypes.MemberExpression &&
|
||||
node.callee.property.type === esTypes.Identifier &&
|
||||
node.callee.object.name === 'unsafeConsole' &&
|
||||
node.callee.property.name
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {VariableDeclarator} node
|
||||
*/
|
||||
const isUnsafeConsoleObjectPatternDeclarator = (node) => {
|
||||
return (
|
||||
node.id.type === esTypes.ObjectPattern &&
|
||||
node.init &&
|
||||
node.init.type === esTypes.Identifier &&
|
||||
node.init.name === 'unsafeConsole'
|
||||
);
|
||||
};
|
||||
|
||||
/** @type {Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
fixable: 'code',
|
||||
schema: [],
|
||||
},
|
||||
create: (context) => ({
|
||||
CallExpression(_) {
|
||||
const node = /** @type {CallExpression} */ (_);
|
||||
|
||||
if (isUnsafeConsoleCall(node)) {
|
||||
context.report({
|
||||
message: ERROR_MSG,
|
||||
loc: node.callee.loc,
|
||||
});
|
||||
}
|
||||
},
|
||||
VariableDeclarator(_) {
|
||||
const node = /** @type {VariableDeclarator} */ (_);
|
||||
|
||||
if (isUnsafeConsoleObjectPatternDeclarator(node)) {
|
||||
context.report({
|
||||
message: ERROR_MSG,
|
||||
loc: node.init.loc,
|
||||
});
|
||||
}
|
||||
},
|
||||
}),
|
||||
};
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
const { RuleTester } = require('eslint');
|
||||
const rule = require('./no_unsafe_console');
|
||||
const dedent = require('dedent');
|
||||
|
||||
const ruleTester = new RuleTester({
|
||||
parser: require.resolve('@typescript-eslint/parser'),
|
||||
parserOptions: {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 2018,
|
||||
},
|
||||
});
|
||||
|
||||
ruleTester.run('@kbn/eslint/no_unsafe_console', rule, {
|
||||
valid: [
|
||||
{
|
||||
code: dedent`
|
||||
unsafeConsole
|
||||
`,
|
||||
},
|
||||
],
|
||||
|
||||
invalid: [
|
||||
{
|
||||
code: dedent`
|
||||
unsafeConsole.debug('something to debug')
|
||||
`,
|
||||
errors: [
|
||||
{
|
||||
line: 1,
|
||||
message: 'Unexpected unsafeConsole statement.',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
code: dedent`
|
||||
unsafeConsole.error()
|
||||
`,
|
||||
errors: [
|
||||
{
|
||||
line: 1,
|
||||
message: 'Unexpected unsafeConsole statement.',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
code: dedent`
|
||||
unsafeConsole.info('some info')
|
||||
`,
|
||||
errors: [
|
||||
{
|
||||
line: 1,
|
||||
message: 'Unexpected unsafeConsole statement.',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
code: dedent`
|
||||
unsafeConsole.log('something to log')
|
||||
`,
|
||||
errors: [
|
||||
{
|
||||
line: 1,
|
||||
message: 'Unexpected unsafeConsole statement.',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
code: dedent`
|
||||
unsafeConsole.trace()
|
||||
`,
|
||||
errors: [
|
||||
{
|
||||
line: 1,
|
||||
message: 'Unexpected unsafeConsole statement.',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
code: dedent`
|
||||
unsafeConsole.warn('something to warn')
|
||||
`,
|
||||
errors: [
|
||||
{
|
||||
line: 1,
|
||||
message: 'Unexpected unsafeConsole statement.',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
code: dedent`
|
||||
unsafeConsole.anyOtherMethodName()
|
||||
`,
|
||||
errors: [
|
||||
{
|
||||
line: 1,
|
||||
message: 'Unexpected unsafeConsole statement.',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
code: dedent`
|
||||
const { debug } = unsafeConsole
|
||||
debug('something to debug')
|
||||
`,
|
||||
errors: [
|
||||
{
|
||||
line: 1,
|
||||
message: 'Unexpected unsafeConsole statement.',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue