Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
fd9069a
add types for network direction processor
couvq Jan 27, 2026
d95f360
added basic network_direction ingest pipeline transpiler and test
couvq Jan 28, 2026
bc9b6d2
thorough testing for ingest pipeline transpiler
couvq Jan 28, 2026
33caef4
add basic esql transpiler and test
couvq Jan 28, 2026
52a71bf
refactor buildIgnoreMissingFilter function to take unlimited source f…
couvq Jan 29, 2026
9426898
handle where clause in esql transpiler
couvq Jan 29, 2026
ef01583
basic nonfunctional network direction ui
couvq Jan 29, 2026
69b0de8
basic nonfunctional network direction ui
couvq Jan 29, 2026
cb34769
add required source ip, destination ip, and target field inputs
couvq Feb 2, 2026
7e1d56d
basic internal networks selector with no content
couvq Feb 2, 2026
1672a3d
custom components for internal networks selector content, placeholder…
couvq Feb 2, 2026
9945b04
setup internal networks
couvq Feb 2, 2026
fd5cab2
internal_networks selection is now exclusive in the ui
couvq Feb 3, 2026
65f7311
collect internal networks with empty field values
couvq Feb 3, 2026
0b9a4dd
internal networks field inputs are now controllable
couvq Feb 3, 2026
7fe915e
add network direction processor description
couvq Feb 3, 2026
b09c10d
basic network direction form now works
couvq Feb 3, 2026
2747baf
fix initial inputs and processor selector
couvq Feb 3, 2026
4474bb0
fix network direction validation on save
couvq Feb 3, 2026
cb1b2d5
add cross compatibility test suite and update snapshot tests
couvq Feb 3, 2026
579bcce
descriptors for yaml mode
couvq Feb 3, 2026
19af265
fix uneccessary props
couvq Feb 3, 2026
e9060a7
changes from claude code review
couvq Feb 3, 2026
0eea768
fix type check error
couvq Feb 3, 2026
8b78167
rebase changes and missing react key
couvq Feb 11, 2026
c5a01a4
fix type check errors caused by scout expect changes and buildIgnoreM…
couvq Feb 11, 2026
fc947e2
Changes from make api-docs
kibanamachine Feb 11, 2026
db8ccd0
Merge branch 'main' into streamlang_network_direction_processor
couvq Feb 11, 2026
7bbcf9d
Merge branch 'main' into streamlang_network_direction_processor
couvq Feb 16, 2026
f199dcb
Merge branch 'main' into streamlang_network_direction_processor
couvq Feb 18, 2026
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
1,922 changes: 1,627 additions & 295 deletions oas_docs/output/kibana.serverless.yaml

Large diffs are not rendered by default.

1,922 changes: 1,627 additions & 295 deletions oas_docs/output/kibana.yaml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
/*
* 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/scout/api';
import type { NetworkDirectionProcessor, StreamlangDSL } from '@kbn/streamlang';
import { transpileEsql, transpileIngestPipeline } from '@kbn/streamlang';
import { streamlangApiTest as apiTest } from '../..';

apiTest.describe(
'Cross-compatibility - Network Direction Processor',
{ tag: ['@ess', '@svlOblt'] },
() => {
apiTest(
'should set network direction with internal networks in both ingest pipeline and ES|QL',
async ({ testBed, esql }) => {
const streamlangDSL: StreamlangDSL = {
steps: [
{
action: 'network_direction',
source_ip: 'source_ip',
destination_ip: 'destination_ip',
internal_networks: ['private'],
} as NetworkDirectionProcessor,
],
};

const { processors } = transpileIngestPipeline(streamlangDSL);
const { query } = transpileEsql(streamlangDSL);

const docs = [
{
source_ip: '128.232.110.120',
destination_ip: '192.168.1.1',
},
];

await testBed.ingest('ingest-e2e-test-network-direction-basic', docs, processors);
const ingestResult = await testBed.getDocs('ingest-e2e-test-network-direction-basic');

await testBed.ingest('esql-e2e-test-network-direction-basic', docs);
const esqlResult = await esql.queryOnIndex('esql-e2e-test-network-direction-basic', query);

expect(ingestResult).toHaveLength(1);
expect(ingestResult[0]?.network.direction).toBe('inbound');
expect(esqlResult.documents).toHaveLength(1);
expect(esqlResult.documents[0]?.['network.direction']).toBe('inbound');
}
);

apiTest(
'should set network direction with target field in both ingest pipeline and ES|QL',
async ({ testBed, esql }) => {
const streamlangDSL: StreamlangDSL = {
steps: [
{
action: 'network_direction',
source_ip: 'source_ip',
destination_ip: 'destination_ip',
target_field: 'test_network_direction',
internal_networks: ['private'],
} as NetworkDirectionProcessor,
],
};

const { processors } = transpileIngestPipeline(streamlangDSL);
const { query } = transpileEsql(streamlangDSL);

const docs = [{ source_ip: '128.232.110.120', destination_ip: '192.168.1.1' }];
await testBed.ingest('ingest-e2e-test-network-direction-target-field', docs, processors);
const ingestResult = await testBed.getDocs(
'ingest-e2e-test-network-direction-target-field'
);

await testBed.ingest('esql-e2e-test-network-direction-target-field', docs);
const esqlResult = await esql.queryOnIndex(
'esql-e2e-test-network-direction-target-field',
query
);

expect(ingestResult).toHaveLength(1);
expect(ingestResult[0]?.test_network_direction).toBe('inbound');
expect(esqlResult.documents).toHaveLength(1);
expect(esqlResult.documents[0]?.test_network_direction).toBe('inbound');
}
);

apiTest(
'should set network direction with internal networks field in both ingest pipeline and ES|QL',
async ({ testBed, esql }) => {
const streamlangDSL: StreamlangDSL = {
steps: [
{
action: 'network_direction',
source_ip: 'source_ip',
destination_ip: 'destination_ip',
internal_networks_field: 'internal_networks',
} as NetworkDirectionProcessor,
],
};

const { processors } = transpileIngestPipeline(streamlangDSL);
const { query } = transpileEsql(streamlangDSL);

const docs = [
{
source_ip: '128.232.110.120',
destination_ip: '192.168.1.1',
internal_networks: ['private'],
},
];

await testBed.ingest(
'ingest-e2e-test-network-direction-internal-networks-field',
docs,
processors
);
const ingestResult = await testBed.getDocs(
'ingest-e2e-test-network-direction-internal-networks-field'
);

await testBed.ingest('esql-e2e-test-network-direction-internal-networks-field', docs);
const esqlResult = await esql.queryOnIndex(
'esql-e2e-test-network-direction-internal-networks-field',
query
);

expect(ingestResult).toHaveLength(1);
expect(ingestResult[0]?.network.direction).toBe('inbound');
expect(esqlResult.documents).toHaveLength(1);
expect(esqlResult.documents[0]?.['network.direction']).toBe('inbound');
}
);

apiTest(
'should set network direction with ignore_missing option in both ingest pipeline and ES|QL',
async ({ testBed, esql }) => {
const streamlangDSL: StreamlangDSL = {
steps: [
{
action: 'network_direction',
source_ip: 'source_ip',
destination_ip: 'destination_ip',
internal_networks: ['private'],
ignore_missing: true,
} as NetworkDirectionProcessor,
],
};

const { processors } = transpileIngestPipeline(streamlangDSL);
const { query } = transpileEsql(streamlangDSL);

const docs = [
{ source_ip: '128.232.110.120', destination_ip: '192.168.1.1' },
{ destination_ip: '192.168.1.1' },
];

await testBed.ingest('ingest-e2e-test-network-direction-ignore-missing', docs, processors);
const ingestResult = await testBed.getDocs(
'ingest-e2e-test-network-direction-ignore-missing'
);

await testBed.ingest('esql-e2e-test-network-direction-ignore-missing', docs);
const esqlResult = await esql.queryOnIndex(
'esql-e2e-test-network-direction-ignore-missing',
query
);

expect(ingestResult).toHaveLength(2);
expect(ingestResult[0]?.network.direction).toBe('inbound');
expect(ingestResult[1]?.network?.direction).toBeUndefined();
expect(esqlResult.documents).toHaveLength(2);
expect(esqlResult.documents[0]?.['network.direction']).toBe('inbound');
expect(esqlResult.documents[1]?.['network.direction']).toBeNull();
}
);

apiTest(
'should set network direction with where condition in both ingest pipeline and ES|QL',
async ({ testBed, esql }) => {
const streamlangDSL: StreamlangDSL = {
steps: [
{
action: 'network_direction',
source_ip: 'source_ip',
destination_ip: 'destination_ip',
internal_networks: ['private'],
where: {
field: 'event.kind',
eq: 'test',
},
} as NetworkDirectionProcessor,
],
};

const { processors } = transpileIngestPipeline(streamlangDSL);
const { query } = transpileEsql(streamlangDSL);

const docs = [
{ source_ip: '128.232.110.120', destination_ip: '192.168.1.1', event: { kind: 'test' } },
{
source_ip: '128.232.110.120',
destination_ip: '192.168.1.1',
event: { kind: 'production' },
},
];

await testBed.ingest('ingest-e2e-test-network-direction-where', docs, processors);
const ingestResult = await testBed.getDocs('ingest-e2e-test-network-direction-where');

await testBed.ingest('esql-e2e-test-network-direction-where', docs);
const esqlResult = await esql.queryOnIndex('esql-e2e-test-network-direction-where', query);

expect(ingestResult).toHaveLength(2);
expect(ingestResult[0]?.network.direction).toBe('inbound');
expect(ingestResult[1]?.network?.direction).toBeUndefined();
expect(esqlResult.documents).toHaveLength(2);
expect(esqlResult.documents[0]?.['network.direction']).toBe('inbound');
expect(esqlResult.documents[1]?.['network.direction']).toBeNull();
}
);
}
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
* 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/scout/api';
import type { NetworkDirectionProcessor, StreamlangDSL } from '@kbn/streamlang';
import { transpileEsql as transpile } from '@kbn/streamlang';
import { streamlangApiTest as apiTest } from '../..';

apiTest.describe(
'Streamlang to ES|QL - Network Direction Processor',
{ tag: ['@ess', '@svlOblt'] },
() => {
apiTest('should set network direction with internal networks', async ({ testBed, esql }) => {
const indexName = 'stream-e2e-test-network-direction-basic';

const streamlangDSL: StreamlangDSL = {
steps: [
{
action: 'network_direction',
source_ip: 'source_ip',
destination_ip: 'destination_ip',
internal_networks: ['private'],
} as NetworkDirectionProcessor,
],
};

const { query } = transpile(streamlangDSL);

const docs = [{ source_ip: '128.232.110.120', destination_ip: '192.168.1.1' }];
await testBed.ingest(indexName, docs);
const esqlResult = await esql.queryOnIndex(indexName, query);

expect(esqlResult.documents).toHaveLength(1);
expect(esqlResult.documents[0]?.['network.direction']).toBe('inbound');
});

apiTest(
'should set network direction with internal networks field',
async ({ testBed, esql }) => {
const indexName = 'stream-e2e-test-network-direction-internal-networks-field';

const streamlangDSL: StreamlangDSL = {
steps: [
{
action: 'network_direction',
source_ip: 'source_ip',
destination_ip: 'destination_ip',
internal_networks_field: 'test_network_direction_field',
} as NetworkDirectionProcessor,
],
};

const { query } = transpile(streamlangDSL);

const docs = [
{
source_ip: '128.232.110.120',
destination_ip: '192.168.1.1',
test_network_direction_field: ['private'],
},
];
await testBed.ingest(indexName, docs);
const esqlResult = await esql.queryOnIndex(indexName, query);

expect(esqlResult.documents).toHaveLength(1);
expect(esqlResult.documents[0]?.['network.direction']).toBe('inbound');
}
);

apiTest(
'should set network direction with ignore_missing option',
async ({ testBed, esql }) => {
const indexName = 'stream-e2e-test-network-direction-ignore-missing';

const streamlangDSL: StreamlangDSL = {
steps: [
{
action: 'network_direction',
source_ip: 'source_ip',
destination_ip: 'destination_ip',
internal_networks: ['private'],
ignore_missing: true,
} as NetworkDirectionProcessor,
],
};

const { query } = transpile(streamlangDSL);

const docs = [
{ source_ip: '128.232.110.120', destination_ip: '192.168.1.1' },
{ destination_ip: '192.168.1.1' },
];
await testBed.ingest(indexName, docs);
const esqlResult = await esql.queryOnIndex(indexName, query);

expect(esqlResult.documents).toHaveLength(2);
expect(esqlResult.documents[0]?.['network.direction']).toBe('inbound');
expect(esqlResult.documents[1]?.['network.direction']).toBeNull();
}
);

apiTest('should set network direction with where condition', async ({ testBed, esql }) => {
const indexName = 'stream-e2e-test-network-direction-where';

const streamlangDSL: StreamlangDSL = {
steps: [
{
action: 'network_direction',
source_ip: 'source_ip',
destination_ip: 'destination_ip',
internal_networks: ['private'],
where: {
field: 'event.kind',
eq: 'test',
},
} as NetworkDirectionProcessor,
],
};

const { query } = transpile(streamlangDSL);

const docs = [
{ source_ip: '128.232.110.120', destination_ip: '192.168.1.1', event: { kind: 'test' } },
{
source_ip: '128.232.110.120',
destination_ip: '192.168.1.1',
event: { kind: 'production' },
},
];
await testBed.ingest(indexName, docs);
const esqlResult = await esql.queryOnIndex(indexName, query);

expect(esqlResult.documents).toHaveLength(2);
expect(esqlResult.documents[0]?.['network.direction']).toBe('inbound');
expect(esqlResult.documents[1]?.['network.direction']).toBeNull();
});
}
);
Loading
Loading