mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[8.x] [Security Solution][Detection Engine] Avoid creating list items for empty lines in import list API (#192681) (#194470)
# Backport This will backport the following commits from `main` to `8.x`: - [[Security Solution][Detection Engine] Avoid creating list items for empty lines in import list API (#192681)](https://github.com/elastic/kibana/pull/192681) <!--- Backport version: 9.4.3 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Marshall Main","email":"55718608+marshallmain@users.noreply.github.com"},"sourceCommit":{"committedDate":"2024-09-30T18:07:39Z","message":"[Security Solution][Detection Engine] Avoid creating list items for empty lines in import list API (#192681)\n\n## Summary\r\n\r\nThe quickstart tooling introduced in\r\nhttps://github.com/elastic/kibana/pull/190634 uses axios under the hood\r\nto make requests to Kibana. When attaching file data to the axios\r\nrequest with `FormData`, axios adds an extra empty line after the end\r\ncontent boundary. The logic in `buffer_lines.ts` assumes that there are\r\nno more lines after the end content boundary line, so importing a list\r\nwith the quickstart tooling would create a list with an extra empty\r\nitem. This empty item fails validation when retrieved through other\r\nAPIs.\r\n\r\nThis PR prevents lines after the end content boundary from being turned\r\ninto list items in the import list API.","sha":"5f83ac05991cd980ef5b205acd19c997b60045a3","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","backport:prev-minor","Team:Detection Engine","v8.16.0"],"title":"[Security Solution][Detection Engine] Avoid creating list items for empty lines in import list API","number":192681,"url":"https://github.com/elastic/kibana/pull/192681","mergeCommit":{"message":"[Security Solution][Detection Engine] Avoid creating list items for empty lines in import list API (#192681)\n\n## Summary\r\n\r\nThe quickstart tooling introduced in\r\nhttps://github.com/elastic/kibana/pull/190634 uses axios under the hood\r\nto make requests to Kibana. When attaching file data to the axios\r\nrequest with `FormData`, axios adds an extra empty line after the end\r\ncontent boundary. The logic in `buffer_lines.ts` assumes that there are\r\nno more lines after the end content boundary line, so importing a list\r\nwith the quickstart tooling would create a list with an extra empty\r\nitem. This empty item fails validation when retrieved through other\r\nAPIs.\r\n\r\nThis PR prevents lines after the end content boundary from being turned\r\ninto list items in the import list API.","sha":"5f83ac05991cd980ef5b205acd19c997b60045a3"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/192681","number":192681,"mergeCommit":{"message":"[Security Solution][Detection Engine] Avoid creating list items for empty lines in import list API (#192681)\n\n## Summary\r\n\r\nThe quickstart tooling introduced in\r\nhttps://github.com/elastic/kibana/pull/190634 uses axios under the hood\r\nto make requests to Kibana. When attaching file data to the axios\r\nrequest with `FormData`, axios adds an extra empty line after the end\r\ncontent boundary. The logic in `buffer_lines.ts` assumes that there are\r\nno more lines after the end content boundary line, so importing a list\r\nwith the quickstart tooling would create a list with an extra empty\r\nitem. This empty item fails validation when retrieved through other\r\nAPIs.\r\n\r\nThis PR prevents lines after the end content boundary from being turned\r\ninto list items in the import list API.","sha":"5f83ac05991cd980ef5b205acd19c997b60045a3"}},{"branch":"8.x","label":"v8.16.0","branchLabelMappingKey":"^v8.16.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> Co-authored-by: Marshall Main <55718608+marshallmain@users.noreply.github.com>
This commit is contained in:
parent
08d5c08021
commit
4c6f2e9317
3 changed files with 47 additions and 63 deletions
|
@ -23,72 +23,15 @@ describe('buffer_lines', () => {
|
|||
}).toThrow('bufferSize must be greater than zero');
|
||||
});
|
||||
|
||||
test('it can read a single line', (done) => {
|
||||
const input = new TestReadable();
|
||||
input.push('line one\n');
|
||||
input.push(null);
|
||||
const bufferedLine = new BufferLines({ bufferSize: IMPORT_BUFFER_SIZE, input });
|
||||
let linesToTest: string[] = [];
|
||||
bufferedLine.on('lines', (lines: string[]) => {
|
||||
linesToTest = [...linesToTest, ...lines];
|
||||
});
|
||||
bufferedLine.on('close', () => {
|
||||
expect(linesToTest).toEqual(['line one']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('it can read a single line using a buffer size of 1', (done) => {
|
||||
const input = new TestReadable();
|
||||
input.push('line one\n');
|
||||
input.push(null);
|
||||
const bufferedLine = new BufferLines({ bufferSize: 1, input });
|
||||
let linesToTest: string[] = [];
|
||||
bufferedLine.on('lines', (lines: string[]) => {
|
||||
linesToTest = [...linesToTest, ...lines];
|
||||
});
|
||||
bufferedLine.on('close', () => {
|
||||
expect(linesToTest).toEqual(['line one']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('it can read two lines', (done) => {
|
||||
const input = new TestReadable();
|
||||
input.push('line one\n');
|
||||
input.push('line two\n');
|
||||
input.push(null);
|
||||
const bufferedLine = new BufferLines({ bufferSize: IMPORT_BUFFER_SIZE, input });
|
||||
let linesToTest: string[] = [];
|
||||
bufferedLine.on('lines', (lines: string[]) => {
|
||||
linesToTest = [...linesToTest, ...lines];
|
||||
});
|
||||
bufferedLine.on('close', () => {
|
||||
expect(linesToTest).toEqual(['line one', 'line two']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('it can read two lines using a buffer size of 1', (done) => {
|
||||
const input = new TestReadable();
|
||||
input.push('line one\n');
|
||||
input.push('line two\n');
|
||||
input.push(null);
|
||||
const bufferedLine = new BufferLines({ bufferSize: 1, input });
|
||||
let linesToTest: string[] = [];
|
||||
bufferedLine.on('lines', (lines: string[]) => {
|
||||
linesToTest = [...linesToTest, ...lines];
|
||||
});
|
||||
bufferedLine.on('close', () => {
|
||||
expect(linesToTest).toEqual(['line one', 'line two']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('two identical lines are collapsed into just one line without duplicates', (done) => {
|
||||
const input = new TestReadable();
|
||||
input.push('--boundary\n');
|
||||
input.push('Content-type: text/plain\n');
|
||||
input.push('Content-Disposition: form-data; name="fieldName"; filename="filename.text"\n');
|
||||
input.push('\n');
|
||||
input.push('line one\n');
|
||||
input.push('line one\n');
|
||||
input.push('--boundary--\n');
|
||||
input.push(null);
|
||||
const bufferedLine = new BufferLines({ bufferSize: IMPORT_BUFFER_SIZE, input });
|
||||
let linesToTest: string[] = [];
|
||||
|
@ -118,9 +61,14 @@ describe('buffer_lines', () => {
|
|||
test('it can read 200 lines', (done) => {
|
||||
const input = new TestReadable();
|
||||
const bufferedLine = new BufferLines({ bufferSize: IMPORT_BUFFER_SIZE, input });
|
||||
input.push('--boundary\n');
|
||||
input.push('Content-type: text/plain\n');
|
||||
input.push('Content-Disposition: form-data; name="fieldName"; filename="filename.text"\n');
|
||||
input.push('\n');
|
||||
let linesToTest: string[] = [];
|
||||
const size200: string[] = new Array(200).fill(null).map((_, index) => `${index}\n`);
|
||||
size200.forEach((element) => input.push(element));
|
||||
input.push('--boundary--\n');
|
||||
input.push(null);
|
||||
bufferedLine.on('lines', (lines: string[]) => {
|
||||
linesToTest = [...linesToTest, ...lines];
|
||||
|
@ -154,6 +102,30 @@ describe('buffer_lines', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('it does not create empty values for lines after the end boundary', (done) => {
|
||||
const input = new TestReadable();
|
||||
input.push('--boundary\n');
|
||||
input.push('Content-type: text/plain\n');
|
||||
input.push('Content-Disposition: form-data; name="fieldName"; filename="filename.text"\n');
|
||||
input.push('\n');
|
||||
input.push('127.0.0.1\n');
|
||||
input.push('127.0.0.2\n');
|
||||
input.push('127.0.0.3\n');
|
||||
input.push('\n');
|
||||
input.push('--boundary--\n');
|
||||
input.push('\n');
|
||||
input.push(null);
|
||||
const bufferedLine = new BufferLines({ bufferSize: IMPORT_BUFFER_SIZE, input });
|
||||
let linesToTest: string[] = [];
|
||||
bufferedLine.on('lines', (lines: string[]) => {
|
||||
linesToTest = [...linesToTest, ...lines];
|
||||
});
|
||||
bufferedLine.on('close', () => {
|
||||
expect(linesToTest).toEqual(['127.0.0.1', '127.0.0.2', '127.0.0.3']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('it can read an empty multi-part message', (done) => {
|
||||
const input = new TestReadable();
|
||||
input.push('--boundary\n');
|
||||
|
|
|
@ -48,7 +48,7 @@ export class BufferLines extends Readable {
|
|||
// we are at the end of the stream
|
||||
this.boundary = null;
|
||||
this.readableText = false;
|
||||
} else {
|
||||
} else if (this.readableText) {
|
||||
// we have actual content to push
|
||||
this.push(line);
|
||||
}
|
||||
|
|
|
@ -49,6 +49,12 @@ describe('write_lines_to_bulk_list_items', () => {
|
|||
test('It imports a set of items to a write buffer by calling "getListItemByValues" with a single value given', async () => {
|
||||
const options = getImportListItemsToStreamOptionsMock();
|
||||
const promise = importListItemsToStream(options);
|
||||
options.stream.push('--boundary\n');
|
||||
options.stream.push('Content-type: text/plain\n');
|
||||
options.stream.push(
|
||||
'Content-Disposition: form-data; name="fieldName"; filename="filename.text"\n'
|
||||
);
|
||||
options.stream.push('\n');
|
||||
options.stream.push('127.0.0.1\n');
|
||||
options.stream.push(null);
|
||||
await promise;
|
||||
|
@ -58,6 +64,12 @@ describe('write_lines_to_bulk_list_items', () => {
|
|||
test('It imports a set of items to a write buffer by calling "getListItemByValues" with two values given', async () => {
|
||||
const options = getImportListItemsToStreamOptionsMock();
|
||||
const promise = importListItemsToStream(options);
|
||||
options.stream.push('--boundary\n');
|
||||
options.stream.push('Content-type: text/plain\n');
|
||||
options.stream.push(
|
||||
'Content-Disposition: form-data; name="fieldName"; filename="filename.text"\n'
|
||||
);
|
||||
options.stream.push('\n');
|
||||
options.stream.push('127.0.0.1\n');
|
||||
options.stream.push('127.0.0.2\n');
|
||||
options.stream.push(null);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue