mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Fix] Replace Osquery query parser lib (#113425)
This commit is contained in:
parent
f79a96fe7f
commit
a7874ff8a5
5 changed files with 75 additions and 52 deletions
|
@ -266,6 +266,7 @@
|
|||
"js-levenshtein": "^1.1.6",
|
||||
"js-search": "^1.4.3",
|
||||
"js-sha256": "^0.9.0",
|
||||
"js-sql-parser": "^1.4.1",
|
||||
"js-yaml": "^3.14.0",
|
||||
"json-stable-stringify": "^1.0.1",
|
||||
"json-stringify-pretty-compact": "1.2.0",
|
||||
|
@ -298,7 +299,6 @@
|
|||
"nock": "12.0.3",
|
||||
"node-fetch": "^2.6.1",
|
||||
"node-forge": "^0.10.0",
|
||||
"node-sql-parser": "^3.6.1",
|
||||
"nodemailer": "^6.6.2",
|
||||
"normalize-path": "^3.0.0",
|
||||
"object-hash": "^1.3.1",
|
||||
|
|
|
@ -73,7 +73,6 @@ export const DEV_ONLY_LICENSE_ALLOWED = ['MPL-2.0'];
|
|||
export const LICENSE_OVERRIDES = {
|
||||
'jsts@1.6.2': ['Eclipse Distribution License - v 1.0'], // cf. https://github.com/bjornharrtell/jsts
|
||||
'@mapbox/jsonlint-lines-primitives@2.0.2': ['MIT'], // license in readme https://github.com/tmcw/jsonlint
|
||||
'node-sql-parser@3.6.1': ['(GPL-2.0 OR MIT)'], // GPL-2.0* https://github.com/taozhi8833998/node-sql-parser
|
||||
'@elastic/ems-client@7.15.0': ['Elastic License 2.0'],
|
||||
'@elastic/eui@38.0.1': ['SSPL-1.0 OR Elastic License 2.0'],
|
||||
|
||||
|
|
9
typings/js_sql_parser.d.ts
vendored
Normal file
9
typings/js_sql_parser.d.ts
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
declare module 'js-sql-parser';
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import { produce } from 'immer';
|
||||
import { find, orderBy, sortedUniqBy, isArray, map } from 'lodash';
|
||||
import { isEmpty, find, orderBy, sortedUniqBy, isArray, map } from 'lodash';
|
||||
import React, {
|
||||
forwardRef,
|
||||
useCallback,
|
||||
|
@ -30,7 +30,7 @@ import {
|
|||
EuiText,
|
||||
EuiIcon,
|
||||
} from '@elastic/eui';
|
||||
import { Parser, Select } from 'node-sql-parser';
|
||||
import sqlParser from 'js-sql-parser';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import styled from 'styled-components';
|
||||
|
@ -615,47 +615,65 @@ export const ECSMappingEditorField = ({ field, query, fieldRef }: ECSMappingEdit
|
|||
return currentValue;
|
||||
}
|
||||
|
||||
const parser = new Parser();
|
||||
let ast: Select;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let ast: Record<string, any> | undefined;
|
||||
|
||||
try {
|
||||
const parsedQuery = parser.astify(query);
|
||||
ast = (isArray(parsedQuery) ? parsedQuery[0] : parsedQuery) as Select;
|
||||
ast = sqlParser.parse(query)?.value;
|
||||
} catch (e) {
|
||||
return currentValue;
|
||||
}
|
||||
|
||||
const tablesOrderMap = ast?.from?.reduce((acc, table, index) => {
|
||||
acc[table.as ?? table.table] = index;
|
||||
return acc;
|
||||
}, {});
|
||||
const tablesOrderMap =
|
||||
ast?.from?.value?.reduce(
|
||||
(
|
||||
acc: { [x: string]: number },
|
||||
table: { value: { alias?: { value: string }; value: { value: string } } },
|
||||
index: number
|
||||
) => {
|
||||
acc[table.value.alias?.value ?? table.value.value.value] = index;
|
||||
return acc;
|
||||
},
|
||||
{}
|
||||
) ?? {};
|
||||
|
||||
const astOsqueryTables: Record<string, OsqueryColumn[]> = ast?.from?.reduce((acc, table) => {
|
||||
const osqueryTable = find(osquerySchema, ['name', table.table]);
|
||||
const astOsqueryTables: Record<string, OsqueryColumn[]> =
|
||||
ast?.from?.value?.reduce(
|
||||
(
|
||||
acc: { [x: string]: OsqueryColumn[] },
|
||||
table: { value: { alias?: { value: string }; value: { value: string } } }
|
||||
) => {
|
||||
const osqueryTable = find(osquerySchema, ['name', table.value.value.value]);
|
||||
|
||||
if (osqueryTable) {
|
||||
acc[table.as ?? table.table] = osqueryTable.columns;
|
||||
}
|
||||
if (osqueryTable) {
|
||||
acc[table.value.alias?.value ?? table.value.value.value] = osqueryTable.columns;
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
return acc;
|
||||
},
|
||||
{}
|
||||
) ?? {};
|
||||
|
||||
// Table doesn't exist in osquery schema
|
||||
if (
|
||||
!isArray(ast?.columns) &&
|
||||
ast?.columns !== '*' &&
|
||||
!astOsqueryTables[ast?.from && ast?.from[0].table]
|
||||
) {
|
||||
if (isEmpty(astOsqueryTables)) {
|
||||
return currentValue;
|
||||
}
|
||||
|
||||
/*
|
||||
Simple query
|
||||
select * from users;
|
||||
*/
|
||||
if (ast?.columns === '*' && ast.from?.length && astOsqueryTables[ast.from[0].table]) {
|
||||
const tableName = ast.from[0].as ?? ast.from[0].table;
|
||||
if (
|
||||
ast?.selectItems?.value?.length &&
|
||||
ast?.selectItems?.value[0].value === '*' &&
|
||||
ast.from?.value?.length &&
|
||||
ast?.from.value[0].value?.value?.value &&
|
||||
astOsqueryTables[ast.from.value[0].value.value.value]
|
||||
) {
|
||||
const tableName =
|
||||
ast.from.value[0].value.alias?.value ?? ast.from.value[0].value.value.value;
|
||||
|
||||
return astOsqueryTables[ast.from[0].table].map((osqueryColumn) => ({
|
||||
return astOsqueryTables[ast.from.value[0].value.value.value].map((osqueryColumn) => ({
|
||||
label: osqueryColumn.name,
|
||||
value: {
|
||||
name: osqueryColumn.name,
|
||||
|
@ -672,39 +690,39 @@ export const ECSMappingEditorField = ({ field, query, fieldRef }: ECSMappingEdit
|
|||
select i.*, p.resident_size, p.user_time, p.system_time, time.minutes as counter from osquery_info i, processes p, time where p.pid = i.pid;
|
||||
*/
|
||||
const suggestions =
|
||||
isArray(ast?.columns) &&
|
||||
ast?.columns
|
||||
?.map((column) => {
|
||||
if (column.expr.column === '*' && astOsqueryTables[column.expr.table]) {
|
||||
return astOsqueryTables[column.expr.table].map((osqueryColumn) => ({
|
||||
isArray(ast?.selectItems?.value) &&
|
||||
ast?.selectItems?.value
|
||||
// @ts-expect-error update types
|
||||
?.map((selectItem) => {
|
||||
const [table, column] = selectItem.value?.split('.');
|
||||
|
||||
if (column === '*' && astOsqueryTables[table]) {
|
||||
return astOsqueryTables[table].map((osqueryColumn) => ({
|
||||
label: osqueryColumn.name,
|
||||
value: {
|
||||
name: osqueryColumn.name,
|
||||
description: osqueryColumn.description,
|
||||
table: column.expr.table,
|
||||
tableOrder: tablesOrderMap[column.expr.table],
|
||||
table,
|
||||
tableOrder: tablesOrderMap[table],
|
||||
suggestion_label: `${osqueryColumn.name}`,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
if (astOsqueryTables && astOsqueryTables[column.expr.table]) {
|
||||
const osqueryColumn = find(astOsqueryTables[column.expr.table], [
|
||||
'name',
|
||||
column.expr.column,
|
||||
]);
|
||||
if (astOsqueryTables && astOsqueryTables[table]) {
|
||||
const osqueryColumn = find(astOsqueryTables[table], ['name', column]);
|
||||
|
||||
if (osqueryColumn) {
|
||||
const label = column.as ?? column.expr.column;
|
||||
const label = selectItem.hasAs ? selectItem.alias : column;
|
||||
|
||||
return [
|
||||
{
|
||||
label: column.as ?? column.expr.column,
|
||||
label,
|
||||
value: {
|
||||
name: osqueryColumn.name,
|
||||
description: osqueryColumn.description,
|
||||
table: column.expr.table,
|
||||
tableOrder: tablesOrderMap[column.expr.table],
|
||||
table,
|
||||
tableOrder: tablesOrderMap[table],
|
||||
suggestion_label: `${label}`,
|
||||
},
|
||||
},
|
||||
|
@ -718,7 +736,6 @@ export const ECSMappingEditorField = ({ field, query, fieldRef }: ECSMappingEdit
|
|||
|
||||
// Remove column duplicates by keeping the column from the table that appears last in the query
|
||||
return sortedUniqBy(
|
||||
// @ts-expect-error update types
|
||||
orderBy(suggestions, ['value.suggestion_label', 'value.tableOrder'], ['asc', 'desc']),
|
||||
'label'
|
||||
);
|
||||
|
|
14
yarn.lock
14
yarn.lock
|
@ -8362,7 +8362,7 @@ better-opn@^2.0.0:
|
|||
dependencies:
|
||||
open "^7.0.3"
|
||||
|
||||
big-integer@^1.6.16, big-integer@^1.6.48:
|
||||
big-integer@^1.6.16:
|
||||
version "1.6.48"
|
||||
resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.48.tgz#8fd88bd1632cba4a1c8c3e3d7159f08bb95b4b9e"
|
||||
integrity sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==
|
||||
|
@ -17523,6 +17523,11 @@ js-sha3@0.8.0:
|
|||
resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840"
|
||||
integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==
|
||||
|
||||
js-sql-parser@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/js-sql-parser/-/js-sql-parser-1.4.1.tgz#775516b3187dd5872ecec04bef8ed4a430242fda"
|
||||
integrity sha512-J8zi3+/yK4FWSnVvLOjS2HIGfJhR6v7ApwIF8gZ/SpaO/tFIDlsgugD6ZMn6flXiuMsCjJxvhE0+xBgbdzvDDw==
|
||||
|
||||
js-string-escape@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef"
|
||||
|
@ -20096,13 +20101,6 @@ node-sass@^6.0.1:
|
|||
stdout-stream "^1.4.0"
|
||||
"true-case-path" "^1.0.2"
|
||||
|
||||
node-sql-parser@^3.6.1:
|
||||
version "3.6.1"
|
||||
resolved "https://registry.yarnpkg.com/node-sql-parser/-/node-sql-parser-3.6.1.tgz#6f096e9df1f19d1e2daa658d864bd68b0e2cd2c6"
|
||||
integrity sha512-AseDvELmUvL22L6C63DsTuzF+0i/HBIHjJq/uxC7jV3PGpAUib5Oe6oz4sgAniSUMPSZQbZmRore6Na68Sg4Tg==
|
||||
dependencies:
|
||||
big-integer "^1.6.48"
|
||||
|
||||
nodemailer@^6.6.2:
|
||||
version "6.6.2"
|
||||
resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.6.2.tgz#e184c9ed5bee245a3e0bcabc7255866385757114"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue