Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Osquery] Add multiline query support #131224

Merged
merged 27 commits into from
May 19, 2022
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b6abc2d
Add multiline query support
tomsonpl Apr 29, 2022
599edb3
Add test to convertSOQueriesToPack
tomsonpl Apr 29, 2022
5470b30
rename
tomsonpl Apr 29, 2022
10702a0
Merge branch 'main' into osquery-multi-line
tomsonpl Apr 29, 2022
c3b34ef
Merge branch 'main' into osquery-multi-line
tomsonpl Apr 29, 2022
7fe8cb8
Merge branch 'main' into osquery-multi-line
kibanamachine May 2, 2022
c0f9b08
add osquery api integration tests
tomsonpl May 2, 2022
d53ca03
Merge remote-tracking branch 'origin/osquery-multi-line' into osquery…
tomsonpl May 2, 2022
da6982c
rename
tomsonpl May 2, 2022
b8f3e7d
rename 2
tomsonpl May 2, 2022
230903b
Merge branch 'main' into osquery-multi-line
kibanamachine May 4, 2022
b6f1c77
adjust tests
tomsonpl May 6, 2022
6691490
remove multi spaces
tomsonpl May 6, 2022
a3de11d
Merge branch 'main' into osquery-multi-line
kibanamachine May 8, 2022
835e720
Merge branch 'main' into osquery-multi-line
kibanamachine May 11, 2022
1d4065f
refactor last results in pack queries table
tomsonpl May 16, 2022
b054da8
Merge branch 'main' into osquery-multi-line
kibanamachine May 16, 2022
da4da32
fix translations
tomsonpl May 16, 2022
57049b6
Merge remote-tracking branch 'origin/osquery-multi-line' into osquery…
tomsonpl May 16, 2022
48cd1a7
change flag in argument to be an option instead removeMultiLines
tomsonpl May 17, 2022
fc1b55c
WIP combine query with aggs
tomsonpl May 17, 2022
69f55b8
fix
patrykkopycinski May 17, 2022
e71c1b7
fix frontend logic
tomsonpl May 18, 2022
4f19f4f
revert logic to the old way
tomsonpl May 18, 2022
637bc9d
Merge branch 'main' into osquery-multi-line
tomsonpl May 18, 2022
268d54a
remove old file
tomsonpl May 18, 2022
b47286a
fix typo
tomsonpl May 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions x-pack/plugins/osquery/public/editor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,7 @@ const OsqueryEditorComponent: React.FC<OsqueryEditorProps> = ({
}) => {
const [editorValue, setEditorValue] = useState(defaultValue ?? '');

useDebounce(() => onChange(editorValue.replaceAll('\n', ' ').replaceAll(' ', ' ')), 500, [
editorValue,
]);
useDebounce(() => onChange(editorValue), 500, [editorValue]);

useEffect(() => setEditorValue(defaultValue), [defaultValue]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -746,11 +746,13 @@ export const ECSMappingEditorField = React.memo(
return;
}

const oneLineQuery = query.replaceAll('\n', ' ').replaceAll(' ', ' ');

// eslint-disable-next-line @typescript-eslint/no-explicit-any
let ast: Record<string, any> | undefined;

try {
ast = sqlParser.parse(query)?.value;
ast = sqlParser.parse(oneLineQuery)?.value;
} catch (e) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { OsqueryAppContext } from '../../lib/osquery_app_context_services';
import { OSQUERY_INTEGRATION_NAME } from '../../../common';
import { PLUGIN_ID } from '../../../common';
import { packSavedObjectType } from '../../../common/types';
import { convertPackQueriesToSO } from './utils';
import { convertPackQueriesToSO, convertSOQueriesToPack } from './utils';
import { getInternalSavedObjectsClient } from '../../usage/collector';

export const createPackRoute = (router: IRouter, osqueryContext: OsqueryAppContext) => {
Expand Down Expand Up @@ -138,7 +138,7 @@ export const createPackRoute = (router: IRouter, osqueryContext: OsqueryAppConte
}

set(draft, `inputs[0].config.osquery.value.packs.${packSO.attributes.name}`, {
queries,
queries: convertSOQueriesToPack(queries, true),
});

return draft;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ export const updatePackRoute = (router: IRouter, osqueryContext: OsqueryAppConte
draft,
`inputs[0].config.osquery.value.packs.${updatedPackSO.attributes.name}`,
{
queries: updatedPackSO.attributes.queries,
queries: convertSOQueriesToPack(updatedPackSO.attributes.queries, true),
}
);

Expand Down
57 changes: 57 additions & 0 deletions x-pack/plugins/osquery/server/routes/pack/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { convertSOQueriesToPack } from './utils';

const getTestQueries = (additionalFields?: Record<string, unknown>, packName = 'default') => ({
[packName]: {
...additionalFields,
query:
'select u.username,\n' +
' p.pid,\n' +
' p.name,\n' +
' pos.local_address,\n' +
' pos.local_port,\n' +
' p.path,\n' +
' p.cmdline,\n' +
' pos.remote_address,\n' +
' pos.remote_port\n' +
'from processes as p\n' +
'join users as u\n' +
' on u.uid=p.uid\n' +
'join process_open_sockets as pos\n' +
' on pos.pid=p.pid\n' +
"where pos.remote_port !='0'\n" +
'limit 1000;',
interval: 3600,
},
});

const oneLiner = {
default: {
ecs_mapping: {},
interval: 3600,
query: `select u.username, p.pid, p.name, pos.local_address, pos.local_port, p.path, p.cmdline, pos.remote_address, pos.remote_port from processes as p join users as u on u.uid=p.uid join process_open_sockets as pos on pos.pid=p.pid where pos.remote_port !='0' limit 1000;`,
},
};

describe('Pack utils', () => {
describe('convertSOQueriesToPack', () => {
test('converts to pack with empty ecs_mapping', () => {
const convertedQueries = convertSOQueriesToPack(getTestQueries());
expect(convertedQueries).toStrictEqual(getTestQueries({ ecs_mapping: {} }));
});
test('converts to pack with converting query to single line', () => {
const convertedQueries = convertSOQueriesToPack(getTestQueries(), true);
expect(convertedQueries).toStrictEqual(oneLiner);
});
test('converts to object with pack names after query.id', () => {
const convertedQueries = convertSOQueriesToPack(getTestQueries({ id: 'testId' }));
expect(convertedQueries).toStrictEqual(getTestQueries({ ecs_mapping: {} }, 'testId'));
});
});
});
10 changes: 6 additions & 4 deletions x-pack/plugins/osquery/server/routes/pack/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@ export const convertPackQueriesToSO = (queries) =>
);

// @ts-expect-error update types
export const convertSOQueriesToPack = (queries) =>
export const convertSOQueriesToPack = (queries, removeMultiLines?: boolean) =>
reduce(
queries,
// eslint-disable-next-line @typescript-eslint/naming-convention
(acc, { id: queryId, ecs_mapping, ...query }) => {
acc[queryId] = {
...query,
(acc, { id: queryId, ecs_mapping, query, ...rest }, key) => {
const index = queryId ? queryId : key;
acc[index] = {
...rest,
query: removeMultiLines ? query.replaceAll('\n', ' ').replaceAll(' ', ' ') : query,
ecs_mapping: convertECSMappingToObject(ecs_mapping),
};

Expand Down
1 change: 1 addition & 0 deletions x-pack/test/api_integration/apis/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,6 @@ export default function ({ loadTestFile }: FtrProviderContext) {
loadTestFile(require.resolve('./ml'));
loadTestFile(require.resolve('./watcher'));
loadTestFile(require.resolve('./logs_ui'));
loadTestFile(require.resolve('./osquery'));
});
}
12 changes: 12 additions & 0 deletions x-pack/test/api_integration/apis/osquery/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

export default function ({ loadTestFile }) {
describe('Osquery Endpoints', () => {
loadTestFile(require.resolve('./packs'));
});
}
76 changes: 76 additions & 0 deletions x-pack/test/api_integration/apis/osquery/packs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import expect from '@kbn/expect';

import { FtrProviderContext } from '../../ftr_provider_context';

const defaultPack = {
tomsonpl marked this conversation as resolved.
Show resolved Hide resolved
name: 'TestPack' + Date.now(),
description: 'TestPack Description',
enabled: true,
policy_ids: ['123', '456'],
queries: {
testQuery: {
query:
'select u.username,' +
' p.pid,' +
' p.name,' +
' pos.local_address,' +
' pos.local_port,' +
' p.path,' +
' p.cmdline,' +
' pos.remote_address,' +
' pos.remote_port' +
'from processes as p' +
'join users as u' +
' on u.uid=p.uid' +
'join process_open_sockets as pos' +
' on pos.pid=p.pid' +
"where pos.remote_port !='0'" +
'limit 1000;',
interval: 600,
platform: 'windows',
version: '1',
},
},
};

const singleLineQuery =
"select u.username, p.pid, p.name, pos.local_address, pos.local_port, p.path, p.cmdline, pos.remote_address, pos.remote_portfrom processes as pjoin users as u on u.uid=p.uidjoin process_open_sockets as pos on pos.pid=p.pidwhere pos.remote_port !='0'limit 1000;";

export default function ({ getService }: FtrProviderContext) {
const supertest = getService('supertest');

describe('Packs', () => {
let newlyCreatedPackId: string = '';
describe('create route', () => {
it('should return 200 and have a single line query', async () => {
const resp = await supertest
.post('/internal/osquery/packs')
.set('kbn-xsrf', 'true')
.send(defaultPack);

newlyCreatedPackId = resp.body.id;
expect(resp.body.attributes.queries.testQuery.query).to.be(singleLineQuery);
expect(resp.status).to.be(200);
});
});
describe('update route', () => {
it('should return 200 and have a single line query', async () => {
const resp = await supertest
.put('/internal/osquery/packs/' + newlyCreatedPackId)
.set('kbn-xsrf', 'true')
.send(defaultPack);

expect(resp.body.id).to.be(newlyCreatedPackId);
expect(resp.body.attributes.queries.testQuery.query).to.be(singleLineQuery);
expect(resp.status).to.be(200);
});
});
});
}